Spring Autowiring when using Configuration Class - java

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

Related

How to use #Value on Spring non-managed class

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;
}
[...]
}

In Spring, annotation and xml must be used together?

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

Spring 4.1.6 - Load ".properties" and initialize a bean with that

I'm new with Spring MVC and I'm doing some tests. I was trying to find some answers about this issues, but most of them make references to Spring 3.11 and I'm using the last release: 4.1.6.
I want to load a ".properties" file when the application starts, and use the information in it to create a bean to access it in all the context of the app.
So far, I reach to load the file in the servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 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">
...
<context:property-placeholder location="classpath*:resources/Resources.properties" />
</beans:beans>
I think (not really sure) that I correctly declared the bean in the root-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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="Resources" class="ar.com.violenciaesmentir.blog.resources.ResourcesDB"/>
</beans>
And I also think I made the bean correctly, but I don't really know if the annotations are right:
package ar.com.violenciaesmentir.blog.resources;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class ResourcesDB {
#Value("DB.NAME")
private String name;
#Value("DB.TYPE")
private String type;
#Value("DB.USER")
private String user;
#Value("DB.PASS")
private String pass;
#Value("DB.DRIVER")
private String driver;
#Value("DB.URL")
private String url;
#Value("DB.MAXACTIVE")
private String maxActive;
#Value("DB.MAXIDLE")
private String maxIdle;
#Value("DB.MAXWAIT")
private String maxWait;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMaxActive() {
return maxActive;
}
public void setMaxActive(String maxActive) {
this.maxActive = maxActive;
}
public String getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(String maxIdle) {
this.maxIdle = maxIdle;
}
public String getMaxWait() {
return maxWait;
}
public void setMaxWait(String maxWait) {
this.maxWait = maxWait;
}
}
My ".properties" file:
DB.NAME = jdbc/Blog
DB.TYPE = javax.sql.DataSource
DB.USER = blog
DB.PASS = blog
DB.DRIVER = oracle.jdbc.driver.OracleDriver
DB.URL = jdbc:oracle:thin:#localhost:1521:xe
DB.MAXACTIVE = 20
DB.MAXIDLE = 5
DB.MAXWAIT = 10000
I think the reference is ok because it gave me troubles when starting the server, saying that it couldn't find the property for "name", but I was doing the annotation wrong and then I fixed.
What I want is to have that bean initialized and be avaible to have an attribute in the DB class like:
#ManagedAttribute
private ResourcesDB resources;
...
public void foo() {
String dbName = resources.getName();
}
When I try it, resources is null. What I'm doing wrong?
-----UPDATE-----
Ok, I could solve the problem doing some try&fail with the answers given. First of all, I corrected the #Value like ("${DB.NAME}") and added a value to the service annotation #Service(value="Resources").
Then, the only change I got to do was in the servlet-context.xml. Instead of:
<context:property-placeholder location="classpath*:resources/Resources.properties" />
I used:
<beans:bean id="configuracion" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location" value="classpath:Resources.properties"/>
</beans:bean>
And used #Autowire instead of #ManagedBean to access the bean.
There are 2 things flawed in your code.
Your #Value expressions are wrong
Your <context:property-placeholder /> must be in the same context as the beans
When using #Value you have to use placeholders, by default ${property name} you are just using a name. So update your annotations to reflect that. I.e. #Value("${DB.NAME}.
Next you have defined <context:property-placeholder /> in the context loaded by the DispatcherServlet whereas your beans are loaded by the ContextLoaderListener. The property placeholder bean is a BeanFactoryPostProcessor and it will only operate on bean definitions loaded in the same context. Basically your bean definition are in the parent context and your placeholder in the child context.
To fix move <context:property-placeholder /> to the same context where you bean is defined in.
Instead of #ManagedAttribute which is a JSF annotation use #Autowired or #Inject. And if you don't have a <context:component-scan /> add a <context:annotation-driven />.
Your #Value syntax is incorrect. It should be #Value("${DB.NAME}").
You might also need to add this to your XML config:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:resources/Resources.properties" />
</bean>
The value on the location may vary, not sure on how you are structuring and building your artifacts.

Autowiring by constructor in Spring creating more objects

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.

AOP using AspectJ not working in spring?

My Aspect class will be ,
#Configuration
#EnableAspectJAutoProxy
#Component
#Aspect
public class AspectClass {
#Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before running the beforeAspect() in the AopTest.java class!");
System.out.println("Hijacked Method name : " + joinPoint.getSignature().getName());
System.out.println("************************");
}
}
My other java Class
public class AopTest {
public void beforeAspect() {
System.out.println("This is beforeAspect() !");
}
}
My Main Class is
public class MainMethod {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("ApplicationContext/applicationContext.xml");
AopTest test = (AopTest)context.getBean("bean1");
test.beforeAspect();
}
}
My applicationContext.xml is ,
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="bean1" class="com.pointel.aop.test1.AopTest" />
</beans>
In this the #Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())") in the AspectClass will not be executed before the beforeAspect() in the AopTest , when running Main method.
Good answers are definitely appreciated.
First of all if you're going to use an annotation based configuration, use AnnotationConfigApplicationContext instead of FileSystemXmlApplicationContext. And get rid of the applicationContext.xml file and simply add a #Bean method in your configuration class. Something like this:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = "your.aspect.package")
public class AspectConfig {
#Bean
public AopTest aopTest() {
return new AopTest();
}
}
In your main
public class MainMethod {
public static void main(String[] args) {
AnnotationConfigApplicationContextcontext = new AnnotationConfigApplicationContext(AspectConfig.class);
// don't forget to refresh
context.refresh();
AopTest test = (AopTest)context.getBean("aopTest");
test.beforeAspect();
}
}
In AspectClass you should have #Component, #Aspect, and your method should have the advice or pointcut annotation like #Before. It needs to be a #Component, so that Spring knows to scan it.
Here some code need to add in xml to use annotations-
1.for #component annotation.
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
2.after that use component scan to get all annotated bean class which use #component annotation,and use aop autoproxy-
<context:annotation-config/>
<context:component-scan base-package="mypackage"></context:component-scan>
<aop:aspectj-autoproxy>
</aop:aspectj-autoproxy>
for examples visit-www.technicaltoday.com/p/spring.html
You are missing the point cut definition in your aspect class.
For example;
#Pointcut("execution(* *.advice(..))")
public void logBefore(){}
#Before("logBefore()")
public void beforeAdvicing(){
System.out.println("Listen Up!!!!");
}
You first have to defin the point to weave your aspect to. You do this by using Point cuts.It is the point cut name you give within your #Before annotation. Have a look at my blog post for more information # http://dinukaroshan.blogspot.com/2010/06/aop-with-spring.html
I don't see your AspectClass in the beans configuration. You should also declare it as a Bean.

Categories

Resources