I have Spring XML configuration file like this:
<bean id="A" class="a.b.c.d.ConfigurationA" />
<bean class="a.b.c.d.ConfigurationB" />
<bean id="C" class="a.b.c.d.e.ConfigurationC" depends-on="objectFromConfigurationB" />
Each configuration file import other config classes. Example:
#Configuration
#Import({ConfigA.class, ConfigB.class})
class ConfigurationA {
#Bean
public ABC abc() {
return new ABC();
}
...
...
..
}
I would like to rewrite this XML config into Java keeping all relations (depends-on). How can I do it?
I tried with:
ComponentScan
Import
always the same: beans from inner configuration files are not loaded into spring context. I caught No bean 'A' available error during startup.
How to create depends-on relation during import configuration bundle?
With component scanning you should not need to do anything.
#Component
class A {
}
#Component {
class B {
}
#Componet {
class C {
private final B b;
#Autowired
C(B b) {
this.b = b;
}
}
Using constructor injection in component C gets you exactly what you want, there is no need to do the depends on. If you are newer versions of spring you don't even need the #Autowired on the constructor.
I converted a project with about 10 XML spring files into Java Configuration. I found that writing #Bean definitions each one in an #Configuration class was not necessary, I thought it would cause bootup times to be faster but made no difference. Using component scanning is lot less code and makes things much simpler. If you are on spring boot you need to make sure that the packages that have code in them are being scanned, for example if you have library in com.example.lib and the #SpringBootApplication class is in com.example.app then the beans in com.example.lib won't be picked up because by default it will scan only the child packages of com.example.app you will need to add more packages to scan to the config or move the main spring boot app class to com.example
You are looking for #DependsOn in your ConfigurationC as follows: #DependsOn("name-of-bean-B").
Related
I and my friend were discussed about #ComponentScan and #Import. Which one is better?
We have 2 different ideas.
#ComponentScan: Easy to use, import all beans from the component
scan.
#Import: You need to know what component you want to use, no need to scan all.
How about your idea? Which one is better for you to use?
Thanks!
#Import is used to import Java configuration classes marked with #Configuration/#Component typically. So if you have a bean inside this component, Spring will load it into Application Context. You can just put the name of the component or class and Spring will pull it up for you.
However, by using #ComponentScan, you tell the application which packages to scan for java classes are annotated with #Configuration/#Component (or any of #Component's sub-annotations like #Service or #Repository etc) and load all of them up in Application Context so they can be autowired when required. If there are inner instances that need to be populated, Spring will take care of it.
You can read more about #Import and #ComponentScan on their respective doc pages.
This page explains pretty well the difference.
#ComponentScan scans and searches for any beans inside packages/classes specified under basePackageClasses or basePackages options, whichever is configured.
This option also allows you to filter some classes that you do not want to be included in search.
#Import is like clubbing one java configuration into another.
eg:
#Configuration
#ComponentScan(basePackages="com.stackoverflow")
public class Dbconfig {
#Bean
public Datasource dSource(){
return new Datasource()
}
}
#Configuration
#Import(Dbconfig.class)
#ComponentScan(basePackages="org.hellospring")
public class AppConfig {
...// beans
}
So here, if we check AppConfig class,
it will include all beans registered in Dbconfig configuration class including inside of package com.stackoverflow
+
It will include all beans inside AppConfig class and beans under package org.hellospring
I've seen other questions related to this issue but none of them actually helps with my issue.
I have these two properties defined in my test class.
#Autowired
private MessagingProperties messagingProperties;
#Autowired
private MessagingPropertiesRefactor messagingPropertiesRefactor;
I am trying to create a new version of MessagingProperties.java. I basically copied this class and create a new file MessagingPropertiesRefactor.java (same package/dir) and pasted the same code. I changed the class definition, etc., but for the most part are the same.
I get an IntelliJ design time compiler error stating that "Could not autowire. No beans of 'MessagingPropertiesRefactor' type not found."
I then searched for every single Usage of the original class to double check if it has been declared somewhere but I have found nothing.
I am "new" to Java (and Spring). Has anyone run into the same issue before?
If your new class MessagingPropertiesRefactor is not annotated with #Component you have got to declare it either in beans.xml like this:
<beans>
<bean name="messagingPropertiesRefactor" class="com.package.path.MessagingPropertiesRefactor"/>
</beans>
or in your AppConfig.java like this:
#Configuration
public class AppConfig {
#Bean
public MessagingPropertiesRefactor messagingPropertiesRefactor() {
return new MessagingPropertiesRefactor();
}
}
Source Reference
If you want to apply Spring dependency injection in tests, you have 2 basic options:
If you want to have the beans declared in XML, declare both MessagingProperties and MessagingPropertiesRefactor in XML file and annotate the test class the following way:
#RunWith(SpringRunner.class)
#ContextConfiguration("your.xml")
The beans should be successfully autowired.
To have the beans declared in JavaConfig, do the following
2.1. Annotate you test class like this:
#RunWith(SpringRunner.class)
#ContextConfiguration
2.2. Inside the test class, define context configuration class that declates the beans that you need:
#Configuration
static class Config {
#Bean
public MessagingProperties messagingProperties() {
// Assuming MessagingProperties has default ctor.
return new MessagingProperties();
}
// Same for MessagingPropertiesRefactor
}
Enjoy the autowired beans :)
*The config class does not have to be nested into the test class.
For more info regarding the topic, please consult Spring documentation: https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-ctx-management-javaconfig, Chapter 3.5.4. Context management.
Ensure that MessagingPropertiesRefactor has all annotations applied to the class that MessagingProperties has. If it has, than look for the bean definition of MessagingProperties in xml configurations for your project and make a copy.
So, I found the "magic" line of code that makes it a "bean".
#EnableConfigurationProperties({MessagingProperties.class, MessagingPropertiesRefactor.class})
public class MessagingConfiguration {
#Autowired
private MessagingProperties messagingProperties;
#Autowired
private MessagingPropertiesRefactor messagingProperties;
So, apparently all I needed to do is add this class to the #EnableConfigurationProperties attribute. Then I can use it anywere by using the #Autowired attribute.
Now... why or how, I don't know (like I said, I am "new" to java) and I would love for someone to elaborate on this.
In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory bean.
Spring documentation defines #Component annotation in the following way: "Indicates that an annotated class is a "component". Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning. "
This is concise, but it does not say a lot. I understand that #Component is used to indicate that a class lifecycle (creation/destruction) will be managed by Spring. The question I have: I need to use it only in classes that will be autowired somewhere (1) or do I also need to use it in classes that have autowired attributes (2)?
(1)
#Component
class B {
}
class A {
// #Autowired
B b;
}
(2)
#Component
class B {
}
#Component
class A {
// #Autowired
B b;
}
Well, strictly speaking you don't have to use anywhere, you can define beans in XML like in the old days. Also you can use #Service or #Repository like in the old days. But back to your question:
If your bean A is not annotated with #Component or otherwise known to the Spring context, it will never be created and managed by Spring. So you either have to use an annotation or define A in XML.
This is true for B as well. If you want it to be a subject for autowiring, it must be known to Spring - either by annotation scanning or by XML.
At the end of the day it doesn't really matter whether you use XML, annotation or Java configuration. It's important that both beans are known to application context.
I'm building a Google App Engine app using Spring 3.1 and am having a problem getting members in one of my jars wired.
I have three projects:
server
server.model
server.persistence
I have an ant build script so that when my workspace builds, it creates jars for server.model and server.persistence, and puts them in the correct lib directory for the server project.
In server, I can autowire things from both server.model and server.persistence, but in server.model my server.persistence beans aren't getting wired even though they're the exact same as in server.
snippet from my servlet application config:
<context:component-scan base-package="com.impersonal.server"/>
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
<bean autowire="byType" id="userList" class="com.impersonal.server.model.UserList"/>
I have the following code in both the server project and the server.model project, and only the server one gets fulfilled. Here's the one failing:
package com.impersonal.server.model;
import java.util.ArrayList;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import com.impersonal.server.persistance.AppEngineDataStore;
import com.impersonal.server.persistance.IDataStore;
public class UserList extends ArrayList<User>
{
private UserList(){}
//this is always null, but the same line in a class in the other project works
private #Autowired AppEngineDataStore _dataStore;
public UserList(UUID userId, String tempId)
{
String poo = "poo";
poo.concat("foo ");
int i = 3;
}
}
Edit:
Just did a test in the server.model project trying to #Autowired something that I don't have defined as a bean in my application config, and didn't get any errors. I should have got a 'no such bean found' error like I do if I do the same thing for the server project.
Any ideas why?
I was instantiating my objects incorrectly. For framework objects and such like MVC controllers, you don't need to do anything to get your #Autowired members wired.
For objects I was creating on the fly, I wasn't going through the IOC container, that's why their dependencies weren't being fulfilled.
<context:component-scan/> tag searches for annotated classes.
If you are going to autowire class using #Autowire annotation, Autowiring class should be annotated with one of stereotype annotation (#Component,#Controller,#Service,#Repository). Spring resolves first annotation configuration and then xml configuration. This is written in spring doc as
Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.
Check proof on spring doc.
So what you need to do is add annotations for classes from server project as well as server.model. Same in case of your third project server.persistence. Add annotations according to layers or functionality.
Try:
#Autowired(required = true)
private AppEngineDataStore _dataStore;
Instead of:
private #Autowired AppEngineDataStore _dataStore;
EDIT 1:
While using the autowire above, in your spring xml, try:
<bean id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" scope="prototype"></bean>
Instead of:
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
autowire in xml means slightly different thing. Instead of defining your bean in xml, you can annotate it as #Service, it will be discovered by the component-scan and the #Autowired will work.
In your xml configuration, use autowire-candidate property
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" autowire-candidate="true" />