I'm trying to get a better understanding of the #Autowired annotations component scanning, but all the examples I found so far use context.getBean(..) at some point to get at least one Bean to start with.
I also read that doing that is considered bad practice , but I can't seem to find any information on how to do it without context.getBean(..)
Could somebody please enlighten me with an example and information on how to do this ?
Define your bean in xml and use
<context:component-scan base-package="com" />
<mvc:annotation-driven />
Bean def
<bean id="processEngine" class="com.processEngine">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
now you can get bean as following
#Autowired
private ProcessEngine processEngine;
how it works
spring scans the bean's recipes either from xml or java configuration. then spring creates a beanDefinitions which are 'loaded' into BeanFactory. BeanFactory triggers a set of BeanPostProcessors (BPP) which are scanning classes for particular annotations like Autowired/Resource/PostProcessor and etc. and do appropriate actions. in case when your class contains #Autowired annotation, AutowiredAnnotationBeanPostProcessor would auto wire required field (dependencies), and when creation of an object is done and all BPP worked out, object is ready to be used by the app, from this point your code can get 'ready' objects from container.
there are some cases when you would need to access this beans from the code which is out of spring's control and not managed by container. in order to do so, you would need to get the ApplicationContext (container) and call #getBean specifying either name or type. using applicationContext directly is not a good practice because there are some problems that you can come to, f.ex. id of a bean might be changed and if you refer to bean by id then NPE would be thrown.
configuration
there are several approaches to configure spring to scan the classes for finding bean recipes. one would be defining component-scan, in this case classes which are located in the path that you've set and having any of valid spring annotations like #Component, #Service, #Repository, #Controller (for web container) would be considered. another way would be specifying each bean separately using <bean> or #Bean.
examples.
if you want to create a web app then you should see DispatcherServlet with ContextLoaderListener classes. this classes would boot your app and load everything according to configuration. f.ex. here,
but if you want to create a desktop app, then you would end up with something like this
From time to time (usually when not using Spring Boot), I use something along the lines of the following code:
public static <T> T autowire(ApplicationContext ctx, T bean) {
ctx.getAutowireCapableBeanFactory().autowireBean(bean);
return bean;
}
In my main, I create an instance of the main application class that contains a few #Autowired annotations for the main services / entry points to my Spring application.
Related
With Spring it is possible to inject a list of beans by the interface class like:
#Component
public class Service {
#Autowire
private List<InterfaceType> implementingBeans;
...
}
All defined beans that implement this interface will be present in this List.
The annotation based approach is not possible for me, as the Service class is in a module that must not have spring dependencies.
I need to use this mechanism from outside via xml configuration.
<bean id="service" class="...Service">
<property name="implementingBeans">
??? tell spring to create a list bean that resolves all beans of the interfaceType.
</property>
</bean>
Does anyone know how to solve this?
EDIT: Additionally, there are more than one spring applications that use this service. So the best solution would be to handle this szenario completely via xml configuration. I can then copy the xml parts to all spriong applications that need this.
I want to avoid having a kind of initializer bean that gets the service injected and must then be copied to all spring applications.
Kind regards.
An XML-only solution would simply have you declare a <bean> of the "external" type and provide an autowire value of "byType".
Controls whether bean properties are "autowired". This is an
automagical process in which bean references don't need to be coded
explicitly in the XML bean definition file, but rather the Spring
container works out dependencies.
[...]
"byType" Autowiring if there is exactly one bean of the property type in the container. If there is more than one, a fatal error is
raised, and you cannot use byType autowiring for that bean. If there
is none, nothing special happens.
The explanation is a little confusing in that we expect multiple InterfaceType beans, but the actual field is of type List and Spring will be able to dynamically instantiate one and add all the InterfaceType beans to it, then inject it.
Your XML would simply look like
<bean id="service" class="...Service" autowire="byType">
</bean>
My original suggested solution made use of SpEL.
In the module that does have Spring dependencies, create a DTO
#Component(value = "beanDTO")
public class BeanDTO {
#Autowire
private List<InterfaceType> implementingBeans;
public List<InterfaceType> getImplementingBeans() {
return implementingBeans;
}
}
and then use SpEL to retrieve the value of implementingBeans from the beanDTO bean.
<bean id="service" depends-on="beanDTO" class="...Service">
<property name="implementingBeans" value="{beanDTO.implementingBeans}" />
</bean>
Spring will create the BeanTDO bean, inject all the beans that are of type InterfaceType. It will then create the service bean and set its property from beanDTO's implementingBeans property.
Following comments on question:
In an effort to be more JSR 330 compliant, Spring has introduced support for Java EE's javax.inject package. You can now annotate your injection targets with #javax.inject.Inject instead of #Autowired. Similarly, you can use #Named instead of #Component. The documentation has more details.
I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.
I have some classes, with a custom annotation, that shouldn't be instantiated (abstract class, and it's just a subcomponents for a real beans). But on top of this classes, on runtime, on context initialization phase, I want to put extra beans into application context.
So, basically I need to scan classpath, process results, and introduce new beans into curent application context.
It seems that spring-mvc, spring-tasks and spring-integration are doing this (I tried to learn it from sources - no luck)
I found that I can create my own BeanFactoryPostProcessor, scan classpath and call registerSingleton for my custom bean. But I'm not sure that it's a good way for introducing new beans (seems that it's used only for postprocess of exising beans only). And I believe there are some Spring internal tools that I may reuse to simplify process.
What is a conventional way to introduce extra beans on Spring context initialization?
Your observation is actually correct, BeanFactoryPostProcessor is one of the two ways Spring provides a mechanism to modify the bean definition/instances before making them available to the application(the other is using BeanPostProcessors)
You can absolutely use BeanFactoryPostProcessors to add/modify bean definitions, here is one sample from Spring Integration codebase that adds a errorChannel if not explicitly specified by a user, you can probably use a similar code for registering your new beans:
RootBeanDefinition errorChannelDef = new RootBeanDefinition();
errorChannelDef.setBeanClassName(IntegrationNamespaceUtils.BASE_PACKAGE
+ ".channel.PublishSubscribeChannel");
BeanDefinitionHolder errorChannelHolder = new BeanDefinitionHolder(errorChannelDef,
IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(errorChannelHolder, registry);
There are at least two ways to include custom annotated classes as bean definitions:
Annotate the custom annotation with #Component
Add a include filter with type annotation to <context:component-scan/>
for example:
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="org.example.Annotation"/>
</context:component-scan>
Then you can use a BeanPostProcessor to instantiate them, for example:
public class CustomAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
#Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass.isAnnotationPresent(org.example.Annotation.class)) {
Object bean = createBeanInstance();
...
return bean:
}
return null;
}
}
Or use a BeanFactoryPostProcessor to process the ScannedGenericBeanDefinitions.
See AnnotationConfigUtils.registerAnnotationConfigProcessors() for sample code of internal Spring annotation postprocessors.
I want to inject a plain java object using Spring programmatically without using any xml configuration. Want to inject fields/methods annotated with tags Like #EJB, #PostConstruct etc. Is that possible? Thanks!
Creating an ApplicationContext without XML (using AnnotationConfigApplicationContext)
With AnnotationConfigApplicationContext, you don't need any XML at all. You create the Application context programatically and either
a) manually register annotated classes
appContext.register( MyTypeA.class,
MyTypeB.class,
MyTypeC.class );
b) or scan the classpath for annotated classes
appContext.scan(
"com.mycompany.myproject.mypackagea",
"com.mycompany.myproject.mypackageb"
)
If you use one of the convenience constructors
AnnotationConfigApplicationContext(Class<?> ... annotatedClasses)
or
AnnotationConfigApplicationContext(String ... basePackages)
the context is created and refreshed automatically, otherwise you need to call the refresh() method manually after adding the classes or packages.
Autowiring existing non-Spring beans (using AutowireCapableBeanFactory)
For autowiring an existing bean I think the preferred idiom is to use
appContext.getAutowireCapableBeanFactory().autowireBean(existingBean)
Or, if you want more control, use
appContext.getAutowireCapableBeanFactory()
.autowireBeanProperties(
existingBean,
autowireMode,
// e.g. AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE
dependencyCheck
)
For further reference, see
ApplicationContext.getAutowireCapeableBeanFactory()
AutowireCapeableBeanFactory.autowireBean(Object existingBean)
AutowireCapeableBeanFactory.autowireBeanProperties(Object
existingBean, int autowireMode,
boolean dependencyCheck)
Yes, you can annotate any POJO with #Component, #Service, #Controller, or #Respository (depending on its responsibilities), and it becomes a spring bean. You just have to put this line into the applicationContext.xml:
<context:component-scan base-package="org.yourbasepackage" />
You can also use #PostConstruct and #PreDestroy instead of the xml init-method and destroy-method.
Update: There is a project called spring-javaconfig. Parts of it have become part of the core spring and you can see more details here. In short, it allows you to use java classes instead of xml for configuring your beans.
The documentation around annotation-based Spring configuration can be found here. You will need a minimal amount of XML, so that Spring knows to look for annotation-based configuration:
<context:component-scan base-package=".." />
Once that is done, you can use the #Autowired annotation to set up your beans.
As I understand it, Spring MVC application has two distinct contexts, the application context and the web context, which are controlled by applicationContext.xml and dispatcher-servlet.xml, respectively.
Inside my controllers, how do I go about loading a bean into either of these contexts?
Note that I am aware of Getting Spring Application Context. That would answer my question for a stand alone application. Where I would use a factory to load the application context from the xml file, but this seems like the wrong way to go about loading beans in Spring MVC.
Matt is absolutely correct. You should not need with any kind of bean-loading/instantiating code in your MVC application, otherwise you're doing something wrong. You define your beans inside the according spring XML configuration files.
<bean id="pinboardServiceTarget" class="com.lifepin.services.PinboardService">
<property name="pinboardEntryDao" ref="pinboardEntryDAO"/>
</bean>
...
<bean id="pinboardEntryDAO" class="com.lifepin.daos.PinboardEntryDAO">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Your PinboardService class (this is just from an application I wrote recently) will have a property IPinboardEntryDAO like
public class PinboardService implements IPinboardService{
private IPinboardEntryDAO pinboardEntryDao;
...
public void setPinboardEntryDAO(IPinboardEntryDAO dao){
this.pinboardEntryDao = dao;
}
public IPinboardEntryDAO getPinboardEntryDAO(){
...
}
...
}
public class PinboardEntryDAO implements IPinboardEntryDAO{
...
}
Note that inside the the PinboardService class I'm using the DAO interface, not the implementation itself, while in the configuration I'm then injecting the real implementation PinboardEntryDAO. This is a very good practice for separating the different layers (presentation, service and data layer).
Although a Spring MVC application has two distinct contexts, the web context has access to all the beans loaded in the application context. The application context however cannot access beans in the web context. This is used to enforce separation of concerns, e.g. business rules class does not need to know about the HTTP session. So if you have a bean you need access to from both contexts it will have to be declared within the application context.
Any dependencies that your Controller has (such as on service-layer classes, DAOs, etc) should be expressed as normal - through injection, either constructor injection or setter injection.
The context where the controller is mapped just wires it up with any dependencies it needs as normal. The Controller code never needs to work with Spring directly to get any beans, it is wired up with them.
You should use dependency injection and your config files to load beans into your controllers, but if you do need to access the application context directly, any Controller that extends AbstractController (or any of its descendents) has access to the getApplicationContext() method.
In stand alone application we can user context.Refresh() it will reloading/re-instantiating the new requested beans the old beans will have the old instance only.
In web applications we need to overwrite the ContextLoaderListener and call the contextInitialized()
You need to import the file containing the bean definitions of the service layer(say, service-context.xml) into the new project. It can be done as:
<import resource="classpath:service-context.xml"/>