In Spring Framework is it possible to eliminate the entire Spring.xml and use a configuration class with #Configuration and #Bean annotation for creating bean, and for all other purpose use a spring.xml?
Yes, you can have pure java configuration in Spring. You have to create a class and annotate it with #Configuration. We annotate methods with #Bean and instantiate the Spring bean and return it from that method.
#Configuration
public class SomeClass {
#Bean
public SomeBean someBean() {
return new SomeBean();
}
}
If you want to enable component scanning, then you can give #ComponentScan(basePackages="specify_your_package") under the #Configuration. Also the method name as someBean serves as bean id. Also if you have to inject a dependency, you can use constructor injection and do as following:
#Configuration
public class SomeClass {
#Bean
public SomeDependency someDependency() {
return new SomeDependency();
}
#Bean
public SomeBean someBean() {
return new SomeBean(someDependency());
}
}
Yes,most of (maybe all of)official guides uses absolutely no xml configuration file,just annotations.
Related
Why do we use qualifiers with #Bean when we can have different names for different beans of the same type (class)?
#Bean
#Qualifier("fooConfig")
public Baz method1() {
}
Isn't the following code more clean?
#Bean("fooConfig")
public Baz method1() {
}
If I create two beans of the same type with different names (using #Bean annotation), then can we inject them specifically using the #Qualifier annotation(can be added on field/constructor parameter/setter) in another bean?
#Bean("fooConfig")
public Baz method1(){
}
#Bean("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
If the above is true, then where do we use #Qualifier (with #Bean or #Component) instead of giving the bean a name as shown below?
#Bean
#Qualifier("fooConfig")
public Baz method1(){
}
#Bean
#Qualifier("barConfig")
public Baz method2(){
}
// constructor parameter of a different bean
final #Qualifier("fooConfig") Baz myConfig
Beans have names. They don't have qualifiers. #Qualifier is annotation, with which you tell Spring the name of Bean to be injected.
No.
Default Qualifier is the only implementation of the interface(example is below, 4th question) or the only method with a particular return type. You don't need to specify the #Qualifier in that case. Spring is smart enough to find itself.
For example:
#Configuration
public class MyConfiguration {
#Bean
public MyCustomComponent myComponent() {
return new MyCustomComponent();
}
}
If you will try to inject myComponent somewhere, Spring is smart enough to find the bean above. Becaude there is only one Bean with return type MyCustomComponent. But if there was a couple of methods, that would return MyCustomComponent, then you would have to tell Spring which one to inject with #Qualifier annotation.
SIDENOTE: #Bean annotation by default Spring uses the method name as a bean name. You can also assign other name like #Bean("otherComponent").
You have one Interface, and a couple of Classes implementing it. You inject bean of your interface. How can Spring know which Class should be used?
This is you interface:
public interface TestRepository{}
This is your implementation 1:
#Repository
public class Test1Repository implements TestRepository{}
Your implementation 2:
#Repository
public class Test2Repository implements TestRepository{}
Now you are injecting it like:
private final TestRepository testRepository;
public TestServiceImpl(TestRepository testRepository) {
this.testRepository= testRepository;
}
QUESTION! How is Spring supposed to know which class to inject? Test1 or Test2? That's why you tell it with #Qualifier which class.
private final TestRepository testRepository;
public TestServiceImpl(#Qualifier("test1Repository") TestRepository testRepository) {
this.testRepository= testRepository;
}
I Prefer different method to not using #Qualifier
Create common Interface
public interface CommonFooBar{
public String commonFoo();
public String commonBar();
}
Extends to each service
public interface FooService extends CommonFooBar {
}
public interface BarService extends CommonFooBar {
}
Then using it to your class
#Autowired
FooService fooService;
or
#Autowired
BarService barService;
so, we can defined the single responsibility to each interface and This kind of segregation is more readable to every junior.
I quite like a different way of working. Surely if you provide a unique name for your bean, then that is all you need?
Given the example below, its easy to see that Spring will name the beans based on the method name used to create the beans. In other words, if you give your beans sensible names, then the code should become self-explanatory. This also works when injecting beans into other classes.
The end result of this is:
Spring will name your beans based on the method used to create them.
If you import a bean, Spring will try to match on the bean name.
If you try to import a bean that does not match the name, Spring will attempt to match the class.
If your injected field name does not match the bean name and there are more than one instance of your bean, Spring will throw an exception on startup as it won't know which one to inject.
Lets not over-complicate Spring.
#Bean
mqConnectionFactory() {
ConnectionFactory connectionFactory = new MQXAConnectionFactory();
return connectionFactory;
}
#Bean
public ConnectionFactory pooledConnectionFactory(ConnectionFactory mqconnectionFactory) {
JmsPoolConnectionFactory connectionFactory = new JmsPoolConnectionFactory();
connectionFactory.setConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public ConnectionFactory cachingConnectionFactory(ConnectionFactory mqConnectionFactory) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setTargetConnectionFactory(mqConnectionFactory);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate(ConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(cachingConnectionFactory);
return jmsTemplate;
}
#Bean
public DefaultMessageListenerContainer messageListenerContainer(ConnectionFactory pooledConnectionFactory) {
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(pooledConnectionFactory);
...
return container;
}
this is a springBoot1.5.22 project.I have 3 java config Bean ,use #Configuration and #Bean annotation.
when i try to run project with debug mode。why myBean method of ConfigurationC execute ? ,the myBean method of ConfigurationA and ConfigurationB not execute。what is mechanism ?
packages of the classes
start class
#Configuration
public class ConfigurationA {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationA myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationB {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationB myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationC {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationC myBean init");
return new MyBean();
}
}
Like #jackycflau said in the comment above, all your beans have the same name.
These three beans, all with the same name and type, are being loaded (but not yet initialized) sequentially into the application context (bean container). When a bean named "myBean" of type MyBean is returned from the application context, you get the one from ConfigurationC because it was the last one written into the container, which overwrote the previous two beans of the same name/type. It's apparently not being initialized until it's actually pulled from the container by client code, which is why it's the only one whose code actually runs.
please provide code snippets to analyse it more.
Bean id should be unique. I don't think you would be allowed to create beans with same beanid.
please try below code
#Configuration
public class ConfigurationA {
#Bean
public MyBean myBean(){
System.out.println("ConfigurationA myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationB {
#Bean
public MyBean myBean1(){
System.out.println("ConfigurationB myBean init");
return new MyBean();
}
}
#Configuration
public class ConfigurationC {
#Bean
public MyBean myBean2(){
System.out.println("ConfigurationC myBean init");
return new MyBean();
}
}
You can try specifying names:
#Bean(name="bean1")
and then select the injected bean:
#Autowired
#Qualifier("bean1")
In Spring Boot 1.5.x the bean overriding is enabled by default.
This means, the bean definition tree is built first and then the last overriding bean is used (executed), all others are ignored (as they were overrided). In your case the last definition comes from ConfigurationC.
This mechanism prevents from ambitious bean definitions, where more than one definition is found, and Spring can't know which one to use - an error occurs (BeanDefinitionOverrideException).
Please note, this must be explicit enabled in Spring Boot 2.x.
I'm not sure if I understand it correctly, but from what I got, is that I can use #Value annotations to read values from my application.properties.
As I figured out this works only for Beans.
I defined such a bean like this
#Service
public class DBConfigBean {
#Value("${spring.datasource.username}")
private String userName;
#Bean
public String getName() {
return this.userName;
}
}
When the application starts I'm able to retrieve the username, however - how can I access this value at runtime?
Whenever I do
DBConfigBean conf = new DBConfigBean()
conf.getName();
* EDIT *
Due to the comments I'm able to use this config DBConfigBean - but my initial problem still remains, when I want to use it in another class
#Configurable
public SomeOtherClass {
#Autowired
private DBConfigBean dbConfig; // IS NULL
public void DoStuff() {
// read the config value from dbConfig
}
}
How can I read the DBConfig in a some helper class which I can define as a bean
Thanks
As Eirini already mentioned you must inject your beans.
The #Value annotation only works on Spring beans.
There is another way of accessing configuration with #ConfigurationProperties.
There you define a class that holds the configuration.
The main advantage is, that this is typesafe and the configuration is in one place.
Read more about this:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-vs-value
You shouldn't instantiate your service with the new operator. You should inject it, for example
#Autowired
private DBConfigBean dbConfig;
and then dbConfig.getName();
Also you don't need any #Bean decorator in your getName() method
You just need to tell spring where to search for your annotated beans. So in your configuration you could add the following:
#ComponentScan(basePackages = {"a.package.containing.the.service",
"another.package.containing.the.service"})
EDIT
The #Value, #Autowired etc annotations can only work with beans, that spring is aware of.
Declare your SomeOtherClass as a bean and add the package config in your #Configuration class
#Bean
private SomeOtherClass someOtherClass;
and then
#Configuration
#ComponentScan(basePackages = {"a.package.containing.the.service"
"some.other.class.package"})
public class AppConfiguration {
//By the way you can also define beans like:
#Bean
public AwesomeService service() {
return new AwesomeService();
}
}
Wrap your DBConfig with #Component annotation and inject it using #Autowired :
#Autowired
private DBConfig dbConfig;
Just add below annotation to your DBConfigBean class:
#PropertySource(value = {"classpath:application.properties"})
I'm new to spring framework, my problem is to register spring component through the spring application context I tried it with many different ways but no luck yet.
#Configuration
#ComponentScan("com.example.app")
#EnableAutoConfiguration
public class ContextDataConfiguration
{
...
}
registered it with
#PostConstruct
public void initilize()
{
AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
beanFactory.initializeBean( new ContextDataConfiguration(), "contextDataConfiguration" );
}
but the other beans specified in the ContextDataConfiguration class are not getting initialized with this approach.
And if I specify the ContextDataConfiguration class in the component scan it is working but it is giving me an error like
not a managed type class
Is there any alternative way to do this?
You can use the #Bean annotation in a factory method to initialize your bean. So, lets say you have a MyBean component and wants to initialize it... You can do this inside your #Configuration class:
#Bean
public MyBean myBean() {
MyBean myBean = ... // initialize your bean here
return myBean;
}
How a about
#Bean
public ContextDataConfiguration contextDataConfiguration(){
return new ContextDataConfiguration();
}
This registers an instance of ContextDataConfiguration as a bean.
I have two methods annotated with #Bean. I am calling one #Bean annotated method from another. Does it mean it creates two beans of the same type?
Here's my code:
#Configuration
#Import({BaseConfig.class})
public class TestConfig{
#Autowired
BaseConfig baseconfig;
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SampleTestClass sampleTest() {
return new SampleTestClass(baseconfig.createNewBean());
}
}
#Configuration
#Import(SomeClassConfig.class)
public class BaseConfig {
#Autowired
private int someAttribute;
#Bean
public SampleTest createNewBean() {
return new SampleTest(someAttribute);
}
}
No, it wouldn't.
SampleTest has a singleton scope which is the default, so even if you call the method "directly", Spring will make sure that there is only one instance per container.
No, it doesn't. Spring automatically proxies #Configuration classes at runtime and decorates #Bean methods to provide the correct scope behavior.
However, in your case it would be cleaner not to tangle the two configurations unnecessarily. Instead, you could do this:
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public SampleTestClass sampleTest(SampleTest dependency) {
return new SampleTestClass(dependency);
}