在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方式:
1package org.xyz.svc.impl; 2 3import org.springframework.beans.BeansException; 4import org.springframework.context.ApplicationContext; 5import org.springframework.context.ApplicationContextAware; 6import org.xyz.svc.UserSvc; 7import org.xyz.vo.User; 8 9public class UserSvcImpl implements UserSvc, ApplicationContextAware{ 10 11 private ApplicationContext context; 12 13 @Override 14 public User initUser() { 15 return (User)context.getBean("User"); 16 } 17 18 @Override 19 public void setApplicationContext(ApplicationContext context) 20 throws BeansException { 21 this.context = context; 22 } 23 24}
applicationContext.xml :
1<?xml version="1.0" encoding="UTF-8"?> 2<!-- 3 - Middle tier application context definition for the image database. 4 --> 5<beans xmlns="http://www.springframework.org/schema/beans" 6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xmlns:tx="http://www.springframework.org/schema/tx" 9 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 10 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 11 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 12 <bean name = "User" class = "org.xyz.vo.User" scope="prototype"></bean> 13 14 <bean name="UserSvc" class = "org.xyz.svc.impl.UserSvcImpl"> 15 </bean> 16 17</beans>
TestCase:
1package test; 2 3import org.junit.Before; 4import org.junit.Test; 5import org.springframework.context.ApplicationContext; 6import org.springframework.context.support.ClassPathXmlApplicationContext; 7import org.xyz.svc.UserSvc; 8 9public class TestUserSvc { 10 11 private ApplicationContext applicationContext; 12 13 @Before 14 public void init() throws Exception{ 15 applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); 16 } 17 18 @Test 19 public void testProcess(){ 20 UserSvc userSvc = (UserSvc)applicationContext.getBean("UserSvc", UserSvc.class); 21 22 System.out.println(userSvc.initUser()); 23 System.out.println(userSvc.initUser()); 24 System.out.println(userSvc.initUser()); 25 } 26 27}
运行结果:
1org.xyz.vo.User@10f6d3 2org.xyz.vo.User@1bcc0bc 3org.xyz.vo.User@111a3a4
这种方式还是与spring framework产生了耦合,可以看到获取User的时候,指定了bean2的名称.
推荐使用下面的lookup方式实现, 因为这种方式使用了代理,spring利用cglib生成了需要的子类.
去掉实现接口ApplicationContextAware, 定义抽象获取user的的方法为抽象方法
1package org.xyz.svc.impl; 2 3import org.xyz.svc.UserSvc; 4import org.xyz.vo.User; 5 6public abstract class UserSvcImpl implements UserSvc{ 7 8 public User initUser() { 9 return createUser(); 10 } 11 12 public abstract User createUser(); 13 14}
applicationContext.xml
1<?xml version="1.0" encoding="UTF-8"?> 2<!-- 3 - Middle tier application context definition for the image database. 4 --> 5<beans xmlns="http://www.springframework.org/schema/beans" 6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xmlns:tx="http://www.springframework.org/schema/tx" 9 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 10 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 11 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 12 <bean name = "User" class = "org.xyz.vo.User" scope="prototype"></bean> 13 14 <bean name="UserSvc" class = "org.xyz.svc.impl.UserSvcImpl"> 15 <lookup-method name="createUser" bean="User"/> 16 </bean> 17 18</beans>
TestCase
略
运行结果:
1org.xyz.vo.User@6f50a8 2org.xyz.vo.User@187814 3org.xyz.vo.User@73a7ab
实现了我们想要的需求了.
注意: 被注入的方法定义要求:
<public|protected> [abstract] <return-type> theMethodName(no-arguments);
如果是抽象方法,会被spring动态生产的子类实现,如果不是抽象,会被覆盖. 所以类和方法修饰符不可以为final.