I'm experimenting with removing all @Components and moving beans into
an xml that could be read by spring to do DI.
This decreases the load time and
Errors:
- Abstract classes annotated as spring components
- Annotations for project which are not included in either build
profiles: usage, simulator, oss (default) and nonoss
- Some project don't even build or are not part of any build
artefacts, looks like the @Component annotation was done in a hurry :)
- Interfaces being annotated as spring components
- Prasanna, Abhi and I spoke with Spring gurus Vijay V and Vaibhav on
how to fix this bloat, so in applicationContext.xml we do some aop
stuff to have transaction stuff we get from @DB annotation and this
needs fixing as it's applying the following for all classes and
methods (dude bloat, run! :)
<aop:config proxy-target-class="true">
<aop:aspect id="dbContextBuilder" ref="transactionContextBuilder">
<aop:pointcut id="captureAnyMethod"
expression="execution(* *(..))"
/>
Methodology and results:
I wrote a python program that would go through the whole source code
and fix all java files (except test, awsapi) who have @Component and
create bean rules in an xml file. Next I had to manually fix few
things (see error above) and I got the mgmt server running, the load
time had improved a lot (little faster now) after disabling
autoscanning and just using the xml generated. I see the benefit of
just using the xml and not having spring as a build time dependency
(we're using @Component in our classes so :).
This was an experiment mostly because a lot of folks are having spring
memory issues, especially Prasanna's devcloud-ci cannot run and check
our commits as memory kills dom0. So, if no one objects may I go ahead
and commit it? For me the jvm took about 650MB real memory on osx.
Right now I made it for all build profiles, nonoss being the superset,
my experiment can be checked out from here:
https://github.com/bhaisaab/cloudstack/tree/spring-annotation-to-xml
Regards.
The python program, in case anyone wants to replicate or is curious:
(defaulter is just a file containing result of: file . | grep java$ >
defaulter)
f = open('defaulter', 'r')
files = f.read().split('\n')[:-1]
files = filter(lambda x: not x.startswith('./awsapi') and
x.find('/test/') == -1, files)
xmldata = ""
bean = """ <bean id="%s" class="%s"/>\n"""
xml = """<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
%s
</beans>
"""
misses = []
for file in files:
name = file.split('/')[-1].split('.')[0]
name = name[0].lower() + name[1:]
pkgname = ""
idx = 0
paths = file.split('/')[1:]
paths[-1] = paths[-1].split('.')[0]
for str in paths:
if str == 'org' or str == 'com':
pkgname = '.'.join(paths[idx:])
idx += 1
f = open(file, 'r')
data = f.read()
f.close()
idx = data.find('@Component')
if idx == -1:
misses.append(file)
continue
string = '@Component'
if data[len(string)+idx] == '(':
endidx = data.find(')', len(string)+idx)
name = data[len(string)+idx+1:endidx].split('=')[-1].replace('"', '')
name = name.replace("'", '')
data = data[:idx] + data[endidx+2:]
else:
data = data.replace(string, '')
data = data.replace('import
org.springframework.stereotype.Component;\n', '')
f = open(file, 'w')
f.write(data)
f.close()
print name, pkgname
xmldata += bean % (name, pkgname)
xmldata += "\n"
xml = xml % xmldata
f = open('./client/tomcatconf/defaultComponentContext.xml.in', 'w')
f.write(xml)
f.close()
f = open('misses', 'w')
f.write('\n'.join(misses))
f.close()