I try to create a Bean and its name using #Bean(value="") attribute. The value should be set with Spring EL Expression.
#Configuration
public class TestClass{
#Autowired
TestProperty testProperty
#Bean(value="#{testProperty.name}")
public MyBean myBean(){
MyBean b = new MyBean();
return b;
}
}
My testProperty is correct injected and holds a value for example testProperty.name = "Bean1"
At the moment my created Bean just have the EL expression as its name: {"bean":"#{testProperty.name}"
How can I give MyBean its name from testProperty.name?
You can use property value for cron attribute of #Scheduled annotation:
#Scheduled(cron = "${testProperty.name}")
So no need for SpEL at all.
Related
I have a bean defined similar to below in my spring.xml. I am converting all my beans into annotation based. How can I inject the attributes in the below listed bean?
<bean
id = "dataPropDao"
class = "com.service.ref.DataPropDaoImpl"
p:dataSource-ref = "data.dataSource"
p:sql = "PROFILE_PKG.GetProfileByCode"
p:function = "true"/>
"p" namespace is used to set bean properties using setters. Equivalent of your code in Java config would be similar to:
#Configuration
class MyConfig {
#Bean
DataPropDaoImpl dataPropDao(DataSource datasource) {
DataPropDaoImpl dao = new DataPropDaoImpl();
dao.setDataSource(datasource);
dao.setSql("PROFILE_PKG.GetProfileByCode");
dao.setFunction(true);
return dao;
}
}
I have a bean like this:
#Bean
public String myBean(){
return "My bean";
}
I want to autowire it:
#Autowired
#Qualifier("myBean")
public void setMyBean(String myBean){
this.myBean=myBean;
}
I need something like:
#Bean(name="myCustomBean")
Is it possible to use custom names names for beans out of the box? If it isn't possible out of the box then how to create such a bean?
What you are asking is already available in Spring reference
By default, configuration classes use a #Bean method’s name as the
name of the resulting bean. This functionality can be overridden,
however, with the name attribute.
#Configuration
public class AppConfig {
#Bean(name = "myFoo")
public Foo foo() {
return new Foo();
}
}
I am reading beginning spring (wiley press) book. In chapter 2 there is an example
about Java configuration and #Autowired. It provides this #Configuration class
#Configuration
public class Ch2BeanConfiguration {
#Bean
public AccountService accountService() {
AccountServiceImpl bean = new AccountServiceImpl();
return bean;
}
#Bean
public AccountDao accountDao() {
AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl();
//depedencies of accountDao bean will be injected here...
return bean;
}
#Bean
public AccountDao accountDaoJdbc() {
AccountDaoJdbcImpl bean = new AccountDaoJdbcImpl();
return bean;
}
}
and this regular bean class
public class AccountServiceImpl implements AccountService {
#Autowired
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
...
}
When I run the code, it works. But I expected an exception because I have defined 2 beans with the same type in the configuration.
I realized it works like this:
if Spring encounters multiple beans with same type it checks field name.
if it finds a bean with the name of the target field, it injects that bean into the field.
Isn't this wrong? Is there a bug in Spring's handling of Java configuration?
The documentation explains this
For a fallback match, the bean name is considered a default qualifier
value. Thus you can define the bean with an id "main" instead of the
nested qualifier element, leading to the same matching result.
However, although you can use this convention to refer to specific
beans by name, #Autowired is fundamentally about type-driven injection
with optional semantic qualifiers. This means that qualifier values,
even with the bean name fallback, always have narrowing semantics
within the set of type matches; they do not semantically express a
reference to a unique bean id
So, no, it's not a bug, that is the intended behavior. The bean id (name) will be used as a fallback if a by-type autowiring doesn't find a single matching bean.
I'm trying to implement fine grained #Autowired configuration using basically the example from the spring documentation at: http://docs.spring.io/spring/docs/3.2.0.RELEASE/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers.
Given the following testcase:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=ExampleConfiguration.class)
public class ExampleTest {
#Autowired #ExampleQualifier(key="x")
private ExampleBean beanWithQualifierKeyX;
#Test
public void test() {
System.out.println(this.beanWithQualifierKeyX);
}
}
and the following configuration:
#Configuration
public class ExampleConfiguration {
#Bean
#ExampleQualifier(key = "x")
public ExampleBean exampleBean1() {
return new ExampleBean();
}
#Bean
#ExampleQualifier(key = "y")
public ExampleBean exampleBean2() {
return new ExampleBean();
}
#Bean
public ExampleBean exampleBean3() {
return new ExampleBean();
}
}
with the custom qualifier annoation:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface ExampleQualifier {
String key();
}
What I would expect is the following: The property beanWithQualifierKeyX should be autowired using the first bean from the configuration class. Both the annotation on the configuration and the annotation on the property have the key="x" setting so this should be the only match. As far as I can see this is almost the same as MovieQualifier annotation from the Spring example documentation.
However, when I execute the test I get the following error:
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private xxx.ExampleBean xxx.ExampleTest.beanWithQualifierKeyX;
nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [xxx.ExampleBean] is defined:
expected single matching bean but found 2: [exampleBean1, exampleBean2]
It looks like Spring does perform a match against the annotation (since both exampleBean1 and exampleBean2 are annotated) but doesn't take into account the value for the key of the annotation - otherwise x would be a perfect match.
Did I miss something in the configuration process or why is there no match?
The Spring version I'm using is 3.2.0.RELEASE
There is/was an bug in Spring 3.2.0 Autowiring with #Qualifier and #Qualifier meta annotation fails in Spring 3.2 (fixed in 3.2.1)
Its description sound exactly like your problem.
So update to 3.2.1
Here's a snippet of a Spring bean:
#Component
public class Bean {
#Value("${bean.timeout:60}")
private Integer timeout;
// ...
}
Now I want to test this bean with a JUnit test. I'm therefore using the SpringJUnit4ClassRunner and the ContextConfiguration annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class BeanTest {
#Autowired
private Bean bean;
// tests ...
#Configuration
public static class SpringConfiguration {
#Bean
public Bean bean() {
return new Bean();
}
}
}
Unfortunately the SpringJUnit4ClassRunner can't resolve the #Value expression, even though a default value is supplied (a NumberFormatException is thrown). It seems that the runner isn't even able to parse the expression.
Is something missing in my test?
Your test #Configuration class is missing an instance of PropertyPlaceholderConfigurer and that's why Spring does not know how to resolve those expressions; add a bean like the following to your SpringConfiguration class
#org.springframework.context.annotation.Bean
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setIgnoreResourceNotFound(true);
return ppc;
}
and move it to a separate class and use
#ContextConfiguration(classes=SpringConfiguration.class)
to be more specific when running your test.