Hard to think of a title for this one! I have a bean that is initialized in a spring container. It loads classes that also create objects from files using Spring classloaders. Some of these objects may have dependencies on expensive objects and I would like those objects to be initialized in the parent. Okay I can't explain in words so on to a simplified example:
public class MainLoader {
public static void main(String[] args) {
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("top-context.xml"));
ChildLoader childLoader = (ChildLoader)beanFactory.getBean("childLoader");
childLoader.loadChildAndDoSomething("message1.xml");
childLoader.loadChildAndDoSomething("message2.xml");
}
}
public class ChildLoader {
public void loadChildAndDoSomething(String childContextfile){
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(childContextfile));
ClassThatDoesStuff classThatDoesStuff = (ClassThatDoesStuff)beanFactory.getBean("classThatDoesStuff");
classThatDoesStuff.saySomething();
}
}
public class ClassThatDoesStuff {
private ReallyExpensiveService reallyExpensiveService;
private String messageStart;
public void saySomething(){
System.out.println(messageStart + reallyExpensiveService.getName());
}
// .. field setters removed for brevity
}
public class ReallyExpensiveService {
public String getName(){
return "Joe";
}
}
These have the following beans in the files:
top-context.xml:
<bean id="childLoader" class="com.mark.test.ChildLoader" />
message1.xml (message2.xml is similar):
<bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff">
<property name="messageStart" value = "Hello! " />
<property name ="reallyExpensiveService" ref="theExpensiveserviceReference" />
</bean>
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />
When these are run you get the expected:
Hello! Joe
Goodbye! Joe
The only problem here is that the "ReallyExpensiveService" is getting created and cached by Spring on each occasion. This is verified by the log. Better to load up any services that might be needed by the "ClassThatDoesStuff" classes (imagine it's an interface) when the MainLoader is initialzed. I.e. (conceptually) change the spring context files to:
top-context.xml:
<bean id="childLoader" class="com.mark.test.ChildLoader" />
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />
message1/2.xml
<bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff"
autoWired="byType">
<property name="messageStart" value = "Hello! " />
</bean>
I realise that the way out of this would be to have the ClassThatDoeStuff have a setter for the service and set the value from the Child container which itself had it injected via the main context. But imagine that there are arbitrary services and each of the ClassThatDoesStuff implementers used different ones.. Is there any way for this to work in Spring..?
It seems like the best you can hope for is to instantiate each ReallyExpensiveService one time. (You mention in there that you're not sure which ClassThatDoesStuff may use a different one.) I would probably try to define all of my ReallyExpensiveService beans in the top level context and then hand them out to the classes that use them wherever it's appropriate, either through the XML configuration files that you're using or through some kind of factory that you inject into the ClassThatDoesStuff beans.
You might also try to look for a way to defer the expensive operations of starting up ReallyExpensiveService until you're sure they're going to be used. Of course this depends on what "expensive" means. Is it that the services use too much memory and you don't want them around if they're not in use or that they take too long to instantiate?
In any case, the key here is to have as few instances of expensive things floating around as possible, so you'll want to configure them at the top level so that the references to the single instances can be passed around anywhere.
I fiddled around a lot with this and learnt a lot about spring in the process. I don't think it's possible to get the parent spring context to apply these properties dynamically. I got around the problem by implementing caching in the mainloader object so that expensive types aren't created multiple times frmo the spring definition.
The other possiblity I investigated was making the ChildLoader context aware and allowing the ClassThatDoesStuff to use the parent context to get handles on beans, but this was bedding in spring to the app too much for my liking.
Related
I am trying to create a generic Logger which would be a small standalone code. Different applications can use this Logger for logging.
Let's say, there are two different codebases- CB1 and CB2.
CB1 needs to capture all public methods of all classes under package- CB1/a/b/c
CB2 needs to capture all public methods of all classes under package- CB2/d/e/f
Now, what I have done till now is as below-
A new codebase, say LogUtility which has an Aspect GenericLogger-
public class GenericLogger {
public Object aroundLog(ProceedingJoinPoint jp) {
//logging code goes here
}
}
in some_context.xml-
<aop:config>
<aop:aspect id="loggerAspect" ref="myLogger">
<aop:pointcut id="sample" expression="${logger.pointcutExpr}" />
<aop:around method="aroundLog" pointcut-ref="sample" />
</aop:aspect>
</aop:config>
If CB1 needs to use this LogUtility, CB1 will add LogUtility to its pom/ivy dependency and provide the value of ${logger.pointcutExpr} via a property file at application startup time.
So, it works fine this way for CB1, CB2,...
The only disadvantage of this approach that I think is the long list in the properties file which has the single key i.e.logger.pointcutExpr
Good thing is, whenever any codebase needs to change it can just add a new pointcut in its own properties file. So a single Aspect can serve multiple codebases.
Earlier, I was trying to do something like this,
#Aspect
#Component
public class GenericLogger {
#Around(<can't make this dynamic>)
public object aroundLog(ProceedingJoinPoint jp) {
//logging code goes here
}
}
The problem with the above is that values passed to any annotation must be final, so can't go with this approach.
I was wondering if there is anything that can be done to achieve this on the fly.
1. Any way in which different codebases can provide the value of the key logger.pointcutExpr without explicitly creating a properties file.
2. Or is it possible to register pointcut with an Aspect on the fly?
I've been googling a lot on this and I'm finding basic AOP tutorials everywhere. I think to do something like this I need to dig deeper in AspectJ along with Spring AOP. I found below links-
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-choosing
how to apply spring aop for legacy code by taking pointcut as input from user
https://eclipse.org/aspectj/doc/next/devguide/ltw-configuration.html
I have basic knowledge of AspectJ, what I'm looking for could be silly.
You can make what is in the Around method dynamic (sort of) by using a static final expression.
But I would suggest something else.
You can definitely do this sort of thing in AspectJ, it's just that you will need to firstly think of the Aspect as describing what expression will execute for the super set of all your cases. Then within the aspect define the behaviour you are wanting to achieve. So for instance you can use Object target = joinPoint.getTarget(); to get the target (class which was executing the method), and then use String canonicalName = taget.getCanonicalName() which will include the package in the name, and then you can do stuff like:
if(getCanonicalName.contains("some/package") {
System.out.println("You can do better than this if statement");
}
And make whatever if statements you need to differentiate between the various packages which are contained in the canonical name. That way you can have greater control over what happens for each package.
I'm using Apache Aries 0.2 in Servicemix 4.3.1 and creating a cm:managed-service-factory. Creation of the services with .cfg files works fine (except for #ARIES-584), but the properties from the .cfg file do not get injected into the service object. They do get set properly in ConfigAdmin, just my bean setter methods never get called for the values in my config file.
I was thinking I should maybe use a cm:managed-properties or something like that nested inside my managed-service-factory, but that would require a separate pid, so doesn't seem right.
If I don't put the property tag in, then no value ever gets set. With the property tag, then just the default value gets set, but never the actual config file value.
I can't find any documentation for usage of the Aries CM subproject, except for blueprint-sample.xml, which doesn't show managed properties inside a managed service factory. I've really been trying to use Servicemix, but around every corner there is missing documentation, broken or missing features, or bugs that affect core functionality.
Both the spring and gemini documentation indicate that their managed-service-factory implementations should also function as managed-properties.
foo.xml:
<blueprint>
<cm:managed-service-factory id="myfoo-msf" factory-pid="my.msf" interface="my.IFoo">
<cm:managed-component class="my.Foo">
<property name="name" value="default />
</cm:managed-component>
</cm:managed-service-factory>
</blueprint>
IFoo.java
package my;
public interface IFoo {
public String getName();
public void setName(String name);
}
Foo.java
package my;
public class Foo implements IFoo {
private String name;
public void setName(String name) {
this.name = name;
System.out.println("name set to: " + name);
}
public String getName() {
return name;
}
}
my.msf-1.cfg
name=name1
my.msf-2.cfg
name=name2
System.out
name set to default
name set to default
config:proplist
service.pid = my.msf.xxxxxxx-xx-xx-xxxxxxxxxxxxxxx
name = name1
service.factoryPid = my.msf
service.pid = my.msf.yyyyyyy-yy-yy-yyyyyyyyyyyyyyy
name = name2
service.factoryPid = my.msf
I believe you have to add one extra line within your managed-component element.
<blueprint>
<cm:managed-service-factory id="myfoo-msf" factory-pid="my.msf" interface="my.IFoo">
<cm:managed-component class="my.Foo">
<cm:managed-properties persistent-id="" update-strategy="container-managed"/>
<property name="name" value="default />
</cm:managed-component>
</cm:managed-service-factory>
</blueprint>
The default value will indeed be overwritten whatever is in your cfg file. If it matters,the default property value setter will be invoked, followed by the same property setter with the value from the cfg.
In this case I have used container-managed for update strategy. But you could use component managed.
This seems kind of redundant to me and in poor taste. Why do I need to set another managed-properties within my bean with a blank persistent id when I have already done so above? Maybe there is a better way but this seems to work.
Also, there is no obvious way to affect the Service Properties that are advertised. For example, we might want to have a convention that any cfg properties that start with service:xxx would be passed through to the Service properties.
Update: The Apache Aries tests are pretty helpful. They can be found here http://aries.apache.org/downloads/currentrelease.html. In particular take a look at the one for configuration management, org.apache.aries.blueprint.cm . In the test folder it has some examples. It shows that in addition to the cm:managed-properties child element within the cm:managed-component shown above, there is also an option to have a cm:cm-properties element within the service-properties.
<service-properties>
<entry key="key" value="foo3" />
<cm:cm-properties persistent-id="" update="true"/>
</service-properties>
Lets say I have a class ListCreator which I want to configure. I want to be able to tell it the sort order and the how to output my table. Therefore I have the boolean sortDescending property and the TableWriter interface which is implemented by PdfTableWriter (but also by XlsTableWriter).
In this example I think configuration and DI go hand in hand. I would like to write something like this Spring (pseudo) example:
<beans>
<bean id="ListCreator" class="ModularListCreator">
<property name="tableWriter">
<ref local="TableWriter"/>
</property>
<property name="sortDescending">
<value>true</value>
</property>
</bean>
<bean id="TableWriter" class="PdfTableWriter"> </bean>
</beans>
Now Spring can do this, but it seems like Weld & Guice can not. Weld for example lets you choose alternatives in the beans.xml, but only for the whole application. What if I want to have one ListCreator for PDFs and another one for XLS at the same time?
I do not get the scope of Weld and Guice at the moment, as they don't seem to allow much of a configuration. The seem to only alleviate the need to write new or to implement your own factories. EJB injection does the same for example, which is nice, but where is the whole configuration part (choosing which instance with what parameters I actually want where).
Coming to the real point: I do not want to use Spring as it seems to be overhead. I much rather use something clean and small at best specified by a JSR. Any suggestions?
Guice actually gives you a lot of power for configuration. Assuming I'm understanding you correctly, here's a simple example of one way you could do this in Guice, using a provider method in a module.
protected void configure() {
bind(TableWriter.class).to(PdfTableWriter.class);
}
#Provides
protected ListCreator provideListCreator(TableWriter tableWriter) {
ModularListCreator result = new ModularListCreator();
result.setTableWriter(tableWriter);
result.setSortDescending(true);
return result;
}
There are other ways too, including making setSortDescending use a binding annotation:
#Inject public void setSortDescending(
#Named("sortDescending") boolean sortDescending)
and then binding that property:
protected void configure() {
bind(TableWriter.class).to(PdfTableWriter.class);
bindConstant().annotatedWith(Names.named("sortDescending")).to(true);
bind(ListCreator.class).to(ModularListCreator.class);
}
For CDI, checkout Seam Solder. It adds the ability to easily configure Managed Beans from an xml file. Judging by the close relationship between the Seam and Weld teams, this mechanism probably has a good chance of making it into a future JSR.
InPUT offers a way if you want a flexible description-based solution. I created the whole example, and added it to the example section.
The code is minimal with:
Design config = new Design("config.xml");
ListCreator creator = config.getValue("ListCreator");
assuming you have a config.xml InPUT design which contains the settings in InPUT syntax:
<SValue id="ListCreator">
<NValue id="SortDescending" value="false"/>
<SValue id="TableWriter" value="Xls"/>
</SValue>
For this to work, you have to define the design space as follows:
<SParam id="ListCreator">
<NParam id="SortDescending" type="boolean" />
<SParam id="TableWriter">
<SChoice id="Xls"/>
<SChoice id="Pdf"/>
</SParam>
</SParam>
You now tailor the programming language independent design space to your Java implementation in a code mapping:
<Mapping id="ListCreator" type="test.ListCreator" constructor="TableWriter SortDescending"/>
<Mapping id="ListCreator.TableWriter" type="test.TableWriter"/>
<Mapping id="ListCreator.TableWriter.Xls" type="test.XlsTableWriter"/>
<Mapping id="ListCreator.TableWriter.Pdf" type="test.PdfTableWriter"/>
From here, extend and customize at free will without touching the code. You mention the case with multiple ListCreator instances. You would have to make 3 changes:
1) design space:
<SValue id="ListCreator" type="[]">
2) design (for example):
<SValue id="ListCreator">
<SValue id="1">
<NValue id="SortDescending" value="true"/>
<SValue id="TableWriter" value="Pdf"/>
</SValue>
<SValue id="2">
<NValue id="SortDescending" value="false"/>
<SValue id="TableWriter" value="Xls"/>
</SValue>
</SValue>
3) Be prepared to receive an array instead (code):
ListCreator[] creators = config.getValue("ListCreator");
You decide the number and alternatives in the descriptor;
the entries arrive in the defined order. This works similar for multiple dimensions (e.g. "[][][]"). You can add alternative table writers with further parameters in the future or change the current parameters without code changes on the caller side. Just make sure the classes are all available, and to test it. There are some sources of error (typos).
I'm having the following problem with Spring: I expected that singletons would be created once and then referenced from the Spring cache. But that does not seem to be the case. I have the following lines in my beans.xml:
<bean id="Cache" class="java.util.HashMap" scope="singleton" >
</bean>
which is referenced below like:
<bean id="ManuallyCachingDAO" class="blah"
scope="singleton" init-method="init" destroy-method="destroy">
<property name="cache" ref="Cache"></property>
...
and in the ManuallyCachingDAO the code:
public Object get(int id) {
Object o = cache.get(id);
if (o != null) {
return o;
}
// ... code for retrieving the object from the DB
}
but the HashMap gets emptied in mysterious ways sometimes! That is, I don't think it's actually emptied. I think it's just dropped and created anew when I reference the ManuallyCachingDAO in another class.
Could you tell me how to fix this problem?
EDIT: At Robin's hint: I do the following to get the beans in a lot of classes (not all though):
ClassPathResource blah = etc.;
XmlBeanFactory xbf = new XmlBeanFactory(blah);
...
xbf.getBean("Cache");
... right now I'm doing it (even for a lot of other beans) ... is that a very stupid or very bad idea or both? I think it occurs to me right now what I'm doing wrong... Until now, I just suspected that all XmlBeanFactories were somehow grabbing the same resources which might have been very dumb indeed, or could s/o tell me what's right?
I doubt that Spring is creating new HashMaps. Your configuration looks OK. I am pretty sure something is wrong in your logic.
In the part marked
// ... code for retrieving the object from the DB
do you actually write the retrieved values to the map?
Maybe concurrency is messing up your map. You don't want to use a HashMap as a singleton since it's not thread safe. Try using ConcurrentHashMap instead.
The config looks fine, and Spring is well tested in this respect so I don't think there are going to be any surprises there.
Would you by any chance be creating the Spring context each time you are trying to access the beans? Thereby recreating everything repeatedly.
As I already have application.properties, where the database connection settings are defined, I decided it is good to put my application-specific settings in that file too. A step further - as spring reads those properties, I declared my Settings bean as follows
<bean name="settingsBean" class="com.tickets.constants.Settings">
<property name="settings">
<props>
<prop key="backup.dir">${backup.dir}</prop>
<prop key="smtp.host">${smtp.host}</prop>
</props>
<property>
</bean>
Now, it happens sometimes, that I need some of those properties in classes that aren't directly in the spring context. Yes - I can either get the spring context from my web application context, or pass the settings as a method parameter to the utility classes, but here's my alternative approach (this is the Settings class):
private static Properties staticSettings;
#PostConstruct
public void init() {
// making the settings available for static access
staticSettings = settings;
}
Now, this looks a bit wrong. But I can't think of a strong reason for not using it.
So to formulate the question - is there any reason not to use my approach, and is there a better one.
You're right, your solution "feels" wrong - the interaction of statics and instance looks like an anti-pattern, but it's a bit of a slippery one to get a grip on.
My gut feeling would be to push the statics a bit further, and make the class itself more internally-consistent, without sacrificing the Spring integration:
public class Settings {
private static Settings instance;
public static Settings initialise(Properties settings) {
instance = new Settings(settings);
return instance;
}
public static Settings get() {
return instance;
}
private final Properties settings;
private Settings(Properties settings) {
this.settings = settings;
}
public String getProperty(String key) {
return settings.getProperty(key);
}
}
Your Spring config would then use factory-method="initialise" rather than the constructor, and other code can use the static get() method to retrieve the singleton. You avoid duplication of the Properties object, and while the static singleton is a bit of an anti-pattern itself, the code makes rather more sense.
But that's the best I can come up with on a freezing cold Saturday morning :)
This is a good question, and I hope you get several informed and well-reasoned responses (better than the one I expect I'm writing).
The reasons for not using this approach are the same as for adopting the Spring framework in the first place: inversion of control, loose coupling, etc. That said, I feel that if you've considered those points in this context and nevertheless feel that this approach elegantly satisfies your actual needs, go right ahead.
Sometimes I feel that Spring -- indeed many leading frameworks & techniques -- allow themselves to slip into "my way or the highway" API design, where the only way to overcome the limitations of Spring is with more Spring.
It shouldn't be that way. You should be able to adopt a thing like Spring in an existing project without signing up to re-architect every bit of your app.
And in fact there are 365236 ways (yours in one) to share objects between the Spring and non-Spring worlds. There's no technical limitation; but the zealots will give you grief.