A class
public class A {
private String name;
public A() {
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
BeanFactory class
public class BeanFactory implements InitializingBean, DisposableBean{
private A a;
public BeanFactory(){
}
public BeanFactory(A a){
this.a = a;
}
public void printAName(){
System.out.println("Class BeanFactory: beanFactory.printAName -> a.getName() = " + a.getName());
}
}
Main
public class Main {
public static void main(String[] args) {
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"ApplicationContext.xml");
BeanFactory beanFactory = applicationContext.getBean("beanFactory",
BeanFactory.class);
beanFactory.printAName();
}
}
ApplicationContext
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="beanFactory" class="testSpring.BeanFactory">
<constructor-arg ref="a1"/>
</bean>
<bean id="a1" class="testSpring.A">
<property name="name" value="I am A!"></property>
</bean>
</beans>
Result of run: Class BeanFactory: beanFactory.printAName -> a.getName() = I am A!
Like you can see, here I don't use no annotation. But the code works thanks to xml file.
So xml doesn't need annotation..? Can I use one or the other?
If I would use, in this application, the annotation (#Autowired for example) instead of bean xml, it's possible? Can you show me how?
Or the annotation must require xml reference?
So.. annotation and xml must be used together? Thanks
You should use annotation configuration, this is the idea
#Component
class Bean1 {
public Bean1() {
System.out.println(getClass());
}
}
#Configuration
#ComponentScan("test")
public class Config {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
}
}
For details see Spring docs
Related
Here my (simplified) code before explaining my problem :
foo.bar.MyFile
public class MyFile extends MyFileAbstract {
#Value("${FILE_PATH}")
private String path;
[...]
public MyFile(final Date date, final String number, final List<MyElement> elements) {
this.date = date;
this.number = number;
this.elements = elements;
}
#Override
public String getPath() {
return path;
}
[...]
}
foo.bar.MyService
#Service
public class MyService {
[...]
public String createFolder(MyFileAbstract file) throws TechnicalException {
[...]
String path = file.getPath();
[...]
}
[...]
}
the call of service
[...]
#Autowired
MyService service;
public void MyMethod() {
MyFile file = new MyFile();
service.createFolder(file);
[...]
}
[...]
I use a context XML to configure Spring :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:property-placeholder
file-encoding="utf-8"
location="file:///[...]/MyProperties.properties" />
<context:annotation-config />
<context:component-scan base-package="foo.bar.classes" />
[...]
</beans>
The problem is that the variable path is null at runtime in both MyService and MyFile file when a instantiate MyFile to call my service MyService.
I am looking a solution to inject my property ${FILE_PATH} inside MyFile.
Here my environment :
Apache Tomcat 7
Java 8
Spring 4.1.6.RELEASE
I have seen that Spring AOP with #Configurable bean could resolve this but don't want to change my Java Agent because I don't want to modify the configuration on the production server.
And I don't know how to use #Service on MyFile with my custom constructor.
Any idea is welcome.
You can add to your MyService
#Autowired
private Environment environment;
and just get the value
environment.getProperty("FILE_PATH");
After that you can set it to the file if necessary.
#Service
public class BeanUtilityService implements ApplicationContextAware {
#Autowired
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
Create a Utility class as a service , create a static method and get the bean from the context.Then use that bean to get the properties required
use #PropertySource annotation
#PropertySource("classpath:config.properties") //use your property file name
public class MyFile extends MyFileAbstract {
#Value("${FILE_PATH}")
private String path;
[...]
public MyFile(final Date date, final String number, final List<MyElement> elements) {
this.date = date;
this.number = number;
this.elements = elements;
}
#Override
public String getPath() {
return path;
}
[...]
}
I have a xml bean file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<bean id="helloWorld" class="com.a.b.HelloWorld">
<property name="attr1" value="Attr1 from XML"></property>
</bean>
<bean id="helloWorld2" class="com.a.b.HelloWorld2">
<property name="attr2" value="Attr2 from XML"></property>
</bean>
</beans>
And I have use constructor autowiring like this
public class HelloWorld2{
private String attr2;
public void setAttr2(String message){
this.attr2 = message;
}
public void getAttr2(){
System.out.println("getAttr2 == " + attr2);
}
}
public class HelloWorld{
private String attr1;
private HelloWorld2 helloWorld2;
public HelloWorld(){
}
#Autowired
public HelloWorld(HelloWorld2 helloWorld2){
System.out.println("hhh");
this.helloWorld2 = helloWorld2;
}
public void setAttr1(String message){
this.attr1 = message;
}
public void getAttr1(){
System.out.println("getAttr1 == " + attr1);
}
public void getH(){
helloWorld2.getAttr2();
}
}
And autowiring is working fine.
Now I want to move my beans to Configuation class.
But then how to move the code so as autowiring works?
I have tried like this, but its not working
#Configuration
public class Config {
#Bean
public HelloWorld helloWorld(){
HelloWorld a = new HelloWorld();
a.setAttr1("Demo Attr1");
return a;
}
#Bean
public HelloWorld2 helloWorld2(){
HelloWorld2 a = new HelloWorld2();
a.setAttr2("Demo Attr2");
return a;
}
}
I think what you want to achieve is the injection of a HelloWorld2 instance into the method that creates the HelloWorld #Bean?
This should do it:
#Configuration
public class Config {
#Bean
public HelloWorld helloWorld(HelloWorld2 helloWorld2){
HelloWorld a = new HelloWorld(helloWorld2);
a.setAttr1("Demo Attr1");
return a;
}
#Bean
public HelloWorld2 helloWorld2(){
HelloWorld2 a = new HelloWorld2();
a.setAttr2("Demo Attr2");
return a;
}
}
This might be a duplication of these questions:
Understanding Spring Autowired usage
Converting Spring XML file to Spring configuration class
Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="foo" class="annotation.Foo">
<property name="name" value="firstFoo"></property>
</bean>
<bean id="secondaryFoo" class="annotation.Foo">
<property name="name" value="secondaryFoo"></property>
<qualifier value="secondaryFoo"></qualifier>
</bean>
<bean id="bar" class="annotation.Bar" />
Bar:
public class Bar {
#Autowired
#Qualifier(value="secondaryFoo")
private Foo foo;
public void setFoo(Foo foo) {
this.foo = foo;
}
public void printFooName(){
System.out.println("\nBar class: foo.getName(): "+foo.getName()+"\n");
}
}
Foo:
public class Foo {
private String name;
public Foo(){
System.out.println("\nFoo class: Constructor invoked, name: "+ name + "\n");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#PostConstruct
public void init() {
System.out.println("\nFoo class: #PostConstruct Bean Foo successfully initialized, name: " + name +"\n");
}
#PreDestroy
public void cleanUp() {
System.out.println("*\nFoo class: #PreDestroy clean up called\n");
}
}
Main:
public class TestFooBar {
public static void main(String[] args) throws InterruptedException {
System.out.println("\nMain invoked\n");
AbstractApplicationContext applicationContext =
new ClassPathXmlApplicationContext("annotation/annotation.xml");
Bar bar = applicationContext.getBean("bar", Bar.class);
bar.printFooName();
}
}
When I run the application the System out are printed in this order:
- Main invoked
- Foo class: Constructor invoked, name: null
- Foo class: #PostConstruct Bean Foo successfully initialized, name: firstFoo
- Foo class: Constructor invoked, name: null
- Foo class: #PostConstruct Bean Foo successfully initialized, name: secondaryFoo
- Bar class: foo.getName(): secondaryFoo
If I specified in the Bar class (#Autowired #Qualifier(value="secondary Foo")) the bean with secondary Foo id, why the beans, in te context, are instantiated both?
If I remove this two annotations, the result of the System out is the same! How it is possible?
You specify both Foo beans in your annotation.xml context, so Spring instantiates both of them (as well as your bar bean).
Then, in addition, it injects secondaryFoo as a dependency into your bar bean.
If you don't want the beans automatically created you could declare them as lazy-init="true" in annotation.xml
I am creating a demo to understand that how can i inject a prototype bean into a singleton bean by using constructor autowiring. Here is my code
My First bean is
public class IndependentBean {
private String independentName;
public IndependentBean()
{
System.out.println("Independent called");
}
public String getIndependentName() {
return independentName;
}
public void setIndependentName(String independentName) {
this.independentName = independentName;
}
}
Now I am creating an independent bean
package com.sample.beans;
public abstract class DependentBean {
private IndependentBean d1;
private IndependentBean d2;
public DependentBean()
{
System.out.println("Default Constructor for dependent");
}
public IndependentBean getD1() {
return d1;
}
public void setD1(IndependentBean d1) {
System.out.println("Setting d1");
this.d1 = d1;
}
public IndependentBean getD2() {
return d2;
}
public void setD2(IndependentBean d2) {
System.out.println("Setting d2");
this.d2 = d2;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public DependentBean(IndependentBean d1) {
System.out.println("With 1");
this.d1 = d1;
}
public DependentBean(IndependentBean d1, IndependentBean d2) {
this.d1 = d1;
this.d2 = d2;
System.out.println("With 2");
}
public abstract IndependentBean getIndependent();
}
Here is my context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">
<bean class="com.sample.beans.IndependentBean" id="firstIn" scope="prototype">
<property name="independentName" value="firstIndependent" />
</bean>
<bean class="com.sample.beans.DependentBean" id="autowireByConstructor"
autowire="constructor">
<lookup-method name="getIndependent" bean="firstIn" />
</bean>
</beans>
Here is my main class
package com.sample.beans;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"classpath:context.xml");
ctx.getBean("autowireByConstructor");
ctx.close();
}
}
According toSpring spec I know that when i am working with autowiring with constructor the constructor with satisfying most dependencies will be called.
However in this case the constructor of independent bean should be call 2 times.but in my case the constructor is called 4 times. I am not getting this clearly.Please help me to understand this ?
Here is the output of the code:
Independent called
Independent called
Independent called
Independent called
With 2
Please help me to understand this behaviour.
I found the answer of this question in Spring Docs.
While we use look-up method injection, Spring uses cglib proxies to fulfill the requirement.When Spring uses cglib proxies the constructor of the target bean called two time.
Hence here in my case Since two proxies of Independent bean will be created and constructor will be called 4 times.
I am learning SPRING and this is not web application code; I am getting NLP while using #Autowired annotation in field level.
Q1) Please help what is wrong?
Q2) If i have #Scope annotation at the class level; do i still need at XML bean level?
#Controller
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
public class StreamingController implements psConsolePortListener.Implementation{
#Autowired
#Qualifier("scMgr")
private StreamingControllerManager streamingMgr = null;
public static void main(String[] args) {
logger.info("StreamingController testing");
XmlBeanFactory factory = new XmlBeanFactory (new ClassPathResource(BEAN_FILE));
StreamingController obj = (StreamingController) factory.getBean("streamingController");
obj.streamingMgr.test();
}
}
#Service
#Scope(value = BeanDefinition.SCOPE_SINGLETON)
#Qualifier("scMgr")
public class StreamingControllerManager {
/** Logger */
private static final Logger logger = LoggerFactory.getLogger(StreamingControllerManager.class);
private StreamingControllerManager(){
logger.info("StreamingControllerManager is called!!");
}
public void test(){
logger.info("StreamingControllerManager test!!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:annotation-config />
<context:component-scan base-package="com.xxx.streamingController"/>
<bean id="scMgr" class="com.xxx.streamingController.StreamingControllerManager">
</bean>
<bean id="streamingController" class="com.xxx.streamingController.StreamingController">
</bean>
</beans>
Output:
Exception in thread "main" java.lang.NullPointerException
at com.pactolus.streamingController.StreamingController.main(
Use an ApplicationContext instead of a BeanFactory.
public static void main(String[] args) {
logger.info("StreamingController testing");
ApplicationContext ctx = new ClassPathXmlApplicationContext(BEAN_FILE);
StreamingController obj = (StreamingController) ctx.getBean("streamingController");
obj.streamingMgr.test();
}
Also remove <context:annotation-config /> that is already impllied by <context:component-scan /> and remove the bean declarations. You are using component-scanning so no need to declare the beans.
Basically leaving you with.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:component-scan base-package="com.xxx"/>
</beans>