在spring中注入方式有3中:
1, 构造函数注入
2, set方法注入
3, 接口注入(方法注入)
在spring中的bean默认范围都是单例, 但是在特定的情况下, 我们需要有如下的业务需要, 单例bean1需要依赖非单例bean2, 由于bean1始终是单例,所以如果不做出改变,每次获取的bean2也是同一个, 容器就没办法给我们提供一个新的bean2.
spring提供了如下方法:
1, 非ioc, 通过bean1实现ApplicationContextAware接口, 利用ApplicatioinContext在需要的时候getBean("bean1");
2, lookup方式
3, 其他
常用的1、2种方式
利用非IOC方式:
package org.xyz.svc.impl;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.xyz.svc.UserSvc;
import org.xyz.vo.User;
public class UserSvcImpl implements UserSvc, ApplicationContextAware{
private ApplicationContext context;
@Override
public User initUser() {
return (User)context.getBean("User");
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = context;
}
}
applicationContext.xml :
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Middle tier application context definition for the image database.
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean name = "User" class = "org.xyz.vo.User" scope="prototype"></bean>
<bean name="UserSvc" class = "org.xyz.svc.impl.UserSvcImpl">
</bean>
</beans>
TestCase:
package test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xyz.svc.UserSvc;
public class TestUserSvc {
private ApplicationContext applicationContext;
@Before
public void init() throws Exception{
applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
}
@Test
public void testProcess(){
UserSvc userSvc = (UserSvc)applicationContext.getBean("UserSvc", UserSvc.class);
System.out.println(userSvc.initUser());
System.out.println(userSvc.initUser());
System.out.println(userSvc.initUser());
}
}
运行结果:
org.xyz.vo.User@10f6d3
org.xyz.vo.User@1bcc0bc
org.xyz.vo.User@111a3a4
这种方式还是与spring framework产生了耦合,可以看到获取User的时候,指定了bean2的名称.
推荐使用下面的lookup方式实现, 因为这种方式使用了代理,spring利用cglib生成了需要的子类.
去掉实现接口ApplicationContextAware, 定义抽象获取user的的方法为抽象方法
package org.xyz.svc.impl;
import org.xyz.svc.UserSvc;
import org.xyz.vo.User;
public abstract class UserSvcImpl implements UserSvc{
public User initUser() {
return createUser();
}
public abstract User createUser();
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Middle tier application context definition for the image database.
-->
<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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean name = "User" class = "org.xyz.vo.User" scope="prototype"></bean>
<bean name="UserSvc" class = "org.xyz.svc.impl.UserSvcImpl">
<lookup-method name="createUser" bean="User"/>
</bean>
</beans>
TestCase
略
运行结果:
org.xyz.vo.User@6f50a8
org.xyz.vo.User@187814
org.xyz.vo.User@73a7ab
实现了我们想要的需求了.
注意: 被注入的方法定义要求:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
如果是抽象方法,会被spring动态生产的子类实现,如果不是抽象,会被覆盖. 所以类和方法修饰符不可以为final.