I am trying to find out what's the best way to use Spring (or not) for loading beans on demand. Here's an example. Let's say that there are two types of mechanic beans
#Bean("japanese-mechanic")
public Mechanic japaneseMechanic(){
return new JapaneseMechanicImpl
}
#Bean("german-mechanic")
public Mechanic germanMechanic(){
return new GermanMechanicImpl
}
My question is how do I load the right bean per request. Currently, the way we do it is using "Context.getBean", so it would look something like
String beanName = request.getParameter("typeOfCar") + "-mechanic";
Mechanic mechanic = Context.getBean(beanName,Mechanic.class);
I understand that calling "Context.getBean" this way violates IOC, so looking for a better way to do this, if available. Can someone suggest some alternatives to doing this? Thanks!
You could avoid accessing the context directly by wiring all the mechanics to your own map like the following:
#Autowired
Map<String, Mechanic> mechanics;
Mechanic mechanic = mechanics.get(beanName);
So instead of fetching the bean from the context map, you autowire them to your own map and fetch them from there. Could be considered better style, or if you have requirements that you can't access the context directly.
Related
Considering the snippet below - is it safe to pass simple not thread-safe HashMap to a SomeHandlerFunction that will use it in other autowired beans in SomeHandlerFunction?
#Bean
RouterFunction<ServerResponse> request(SomeHandlerFunction handlerFunction) {
handlerFunction.setSimpleMapProperties(new HashMap());
return route(GET("/dummy"), handlerFunction);
}
#Service
class SomeHandlerFunction implements HandlerFunction {
#Autowired
List<AnotherBeans> anotherBeans;
Mono<T> handle(ServerRequest var1) {
// code...
}
}
I'm a bit aware about multithreading model in WebFlux, but this case made me confusing.
If that HashMap is mutable, it's not a good idea - not even with Spring MVC.
What should you do instead? It really depends on the use case at hand.
If you're trying to setup a local in-memory cache, you could use a library like Caffeine, or simply a ConcurrentMapCache.
If you'd like to share configuration keys with that bean, you could wrap that map with Collections.unmodifiableMap or even better, make that a proper immutable POJO.
If this is meant to carry temporary data that's linked with the request being processed, you should instead use request attributes or Reactor Context for that.
In my ApplicationContext I have several Beans being created the same style. So I have a lot of dublicated code writing a FactoryBean for each of this beans. Those beans have a common ground, implementing all one special interface.
I would like to move all that bean creation to one factory. That one would have to provide a methode like this
<T extends CommonInterface> T createInstance(Class<T> clazz);
There I could implement all the instantiation necessary to create one of my special beans.
My implementation would be called by spring for
#Autowired
private MyCommonInterfaceImplementation impl;
in that way
createInstance(MyCommonInterfaceImplementation.class)
So far I looked at BeanFactory and FactoryBean, both seem not to be I'm searching for.
Any suggestions?
why not use #bean
#Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
#Autowired
private MyCommonInterfaceImplementation impl;
Basically you need the #Bean annotation on a "factory" only if you need some special handling during the creation of a bean.
If everything can be #Autowired, either by setters, fields, or one constructor, and nothing else needs to be done on a bean during initialization, you can simply declare the annotation #Component on each implementation of your interface. This works as long as you have component scanning active inside your application. The result will be that for each component spring will create a bean which you can use.
I'm writing this on a mobile so showing code is not the best. Just follow some tutorial on #ComponentScan, or if you need, let me know and I can augment this answer with an example.
As of Spring 4.3 you no longer have to annotate your bean classes and you can let them be instantiated via a componentscan.
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
This actually creates beans for the three classes listed there. The example should work without filters as well (everything in the package becomes a bean). This works as long as the classes have a single constructor that can be used for autowiring. I don't think it is possible to filter for all implementations of a particular interface and then register a bean.
To do that, you might do something with a ContextListener and e.g. use reflection to find out what classes to instantiate and then use context.autowire(..) to inject any dependencies from your context. A bit hacky but it might work.
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
That still leaves the problem of how to get the bean registered in the context of course.
You might also be able to adapt the answer to this SO question on how to add beans programmatically.
Finally the best approach I've found is using a ConfigurationClassPostProcessor. As example I've used https://github.com/rinoto/spring-auto-mock
But, since it is quite complicated and "too much magic" to create beans from nothing, we decided to explicitly create those beans via #Bean.
Thanks for your answers.
I am implementing a multi-tenant application. Many of my resources have paths like "/api/tenant/{tenant_id}/resource/path/". What I would like to do is to inject different DAOs (or possibly other objects) to the resource based on the "{tenant_id}" path parameter.
I have two suboptimal ideas on how to achieve something similar:
Use a wrapper class like this:
class SomeDAOWrapper
{
SomeDAO getSomeDAO()
{
return new SomeDAO(tenantId_m);
// Alternatively we could store the DAOs in some hash-table
// with tenantId_m as the key.
}
#PathParam("tenant_id")
private long tenantId_m;
}
Then in my resource class I would have SomeDAOWrapper as an attribute annotated with #BeanParam.
Use a sub-resource locator on path "/api/tenant/{tenant_id}" that would return the resources with the correct DAOs.
Any other ideas? Ideally what I would like to do is to simply have SomeDAO attribute in my resource class that is annotated with #Inject or something similar (and that would use some factory that takes the tenant_id path parameter into account).
I ran into this same kind of problem and ended up using the guice multibinder solution. You essentially bind your Dao's to a MultiBinder and then Inject a factory into your service. This was the cleanest solution I could come up with for the problem.
Check out this url, it is pretty much what I did to get dependency injection working with a resource that needed a specific dao.
https://groups.google.com/forum/#!topic/google-guice/J6S77sILTAY
We have a homepage that contains multiple components (widgets), kinda like a portal containing portlets. Some of these widgets will be delivered ad jars from other teams and some of those will require some custom beans to be managed by Spring. One solution might be to import spring contexts using the import statement with I wildcard (e.g. import all contexts in the classpath matching context-widget-*.xml).
However, I prefer a more programmatic solution where I check for each widget which context they need loaded (from the classpath). I did not find any blog or such that explains this but did find some posts on forums that explain that this would be a parent-child context and this will only be unidirectional; unfortunately in my case it needs to be bidirectional.
So after some browsing in the API I managed to come up with something working but I am not confident it is a good solution or it there are any pitfalls I did not think about. Perhaps there is another (better) solution for this scenario?
public class WidgetManager implements ApplicationContextAware
{
#Autowired
private WidgetService widgetService;
#Override
public void setApplicationContext(ApplicationContext parentApplicationContext) throws BeansException {
//I do need the parent context to have finished initializing beans
List<WidgetTO> widgets = widgetService.findAllWidgets();
List<String> contexts = newArrayListWithCapacity(widgets.size());
for (WidgetTO widget : widgets) {
if (isNotBlank(widget.getSpringContext())) {
contexts.add(widget.getSpringContext());
}
}
AbstractRefreshableWebApplicationContext parentContext = (AbstractRefreshableWebApplicationContext) parentApplicationContext;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(contexts.toArray(new String[] {}), parentApplicationContext);
String[] singletonNames = context.getBeanFactory().getSingletonNames();
for (String s : singletonNames) {
//copy all singletons that don't already exist from child to parent
if (!parentContext.getBeanFactory().containsSingleton(s)) {
parentContext.getBeanFactory().registerSingleton(s, context.getBeanFactory().getSingleton(s));
}
}
}
}
This is actually exactly how I did it. We have been using this fashion for over 3 years and never had issues.
You might be able to use AutowireCapableBeanFactory. This class lets you add beans to your existing Spring context. It will instantiate beans and inject their dependencies.
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/AutowireCapableBeanFactory.html
I'm not sure I understand the "bidirectional" context thing you're talking about. Do you need your primary context beans to have dependencies on beans from the "child"/additional contexts? If so, wildcard imports are probably your best bet, even if you don't prefer that solution.
It might be helpful if you explained in a little more detail your overall application lifecycle, describing the stages for your "parent"/primary context and your "child"/additional contexts.
Is there a way to auto-cast Spring beans to the class defined in the application context XML? I'd like to avoid putting type information about the beans in 2 places.... in the xml configuration file and also in the code as a cast.
For instance, given this config file
<bean id="bean-name" class="SimpleSpringBean" scope="prototype">
<property name="myValue" value="simple value"></property>
</bean>
Can I call ApplicationContext.getBean("bean-name") in such a way as to avoid directly casting the return type to SimpleStringBean. I know I can also call ApplicationContext.getBean("bean-name", SimpleSpringBean.class) to avoid the cast itself, but I still have the type info in 2 places.
It seems that Spring can get the class info (ApplicationContext.getType) or by getting the type from the bean itself, but no way to automatically cast the type without programmer intervention.
I agree with Sii, you should avoid calling getBean as much as you can. Just wire your beans to classes that depends on them.
Still, if you have a single class that holds the application context, you can provide a wrapper generic method like the following:
class MyContextHolder{
ApplicationContext appContext;
......
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName)
{
return (T)appContext.getBean(beanName);
}
}
Then you can call it without casting
MyClass mc = MyContextHolder.getBean("myClassBean");
The answer is you shouldn't be using ApplicationContext.getBean() at all if it's possible, and bear with the one place you have to in the bootstrap code. (Generally, you should never need to use getBean() outside of your application's entry points.)
Also, what you're asking is likely impossible in the Java language at all. Casting is a compile-time feature, combined with a runtime check. The return type of getBean() simply must be known at compile time. Even if Spring can determine the type of an object, it can't change its own method signatures at runtime.
Another thing is that even if this were possible, the feature wouldn't be all that useful. Because Spring AOP is implemented using dynamic proxies, you nearly always want Spring to hand you an instance of an interface the bean implements (which could be an AOP proxy), not of the implementation class.
Another approach I also use is autowiring the bootstrapping class using:
public class Main {
#Autowired FooFacade foo;
#Autowired BarFacade bar;
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("appCtx.xml");
AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();
Object main = bf.createBean(Main.class,
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT,
false);
((Main) main).run();
}
private void run() {
foo.doBootstrapStuff();
bar.doMoreBootstrapStuff();
}
}
(Code done from memory. Might only work if you have the Spring context configured to process wiring annotations, in that case making setters for foo and bar should work.)
The main reason for getBean being untyped is the compatibility of Spring (up to version 2.5.x) with Java 1.4. Spring 3.0 will drop that and thus offer typed getBean method then.
Nevertheless you should avoid looking up beans directly and minimize its usage as far as possible.
What if I use Spring as an object factory that my application uses extensively.
That is, instead of writing a bunch of classes that already inherit or wrap around
known Java classes I just decide to move all that into an xml file to cut down on
lines of Java code. This will mean many lines of xml but I won't need to make
skeleton Java classes which I inject with Spring or autowire. Thus making the lines
of Java code less.
For this reason and still as I am new to Spring I have just as stated in previous
posts used static Java methods which wrap around the getBeans().
I have worked with Spring but it is still new to me so forgive my question.
"Because Spring AOP is implemented using dynamic proxies, you nearly always want Spring to hand you an instance of an interface the bean implements (which could be an AOP proxy), not of the implementation class"
So there is no way to get a dynamic proxy using getBean(), then whats the best practice if there are no interfaces and its a stand alone driver class to be executed?