spring-bean(三)
配置方式:通过工厂方法配置bean,通过FactoryBean配置bean
配置形式:基于注解的方式
组件扫描
泛型依赖注入
静态工厂方法
1 /** 2 * 静态工厂方法:直接调用某一个类的静态方法就可以返回bean的实例 3 */ 4 public class StaticCarFactory { 5 private static Map<String, Car> cars = new HashMap<String, Car>(); 6 7 static{ 8 cars.put("audi", new Car("audi",123,123)); 9 cars.put("ford", new Car("ford",123,123)); 10 } 11 12 public static Car getCar(String name) { 13 return cars.get(name); 14 } 15 }
1 <!-- 通过静态工厂方法来配置bean,注意不是配置静态工厂方法实例,而是配置bean实例 --> 2 <bean id="car1" class="com.text.StaticCarFactory" factory-method="getCar"> 3 <constructor-arg value="audi"></constructor-arg> 4 </bean>
实例工厂方法
1 /** 2 * 实例工厂方法:实例工厂的方法,即先需要创建工厂本身,在调用 3 * 工厂的实例方法,再配置bean的实例 4 */ 5 public class InstanceCarFactory { 6 7 private Map<String, Car> cars = null; 8 9 public InstanceCarFactory() { 10 cars = new HashMap<String, Car>(); 11 cars.put("audi", new Car("audi",123,123)); 12 cars.put("ford", new Car("ford",123,123)); 13 } 14 15 public Car getCar(String name) { 16 return cars.get(name); 17 } 18 }
1 <!-- 配置工厂的实例 --> 2 <bean id="carFactory" class="com.text.InstanceCarFactory"></bean> 3 <!-- 通过实例工厂方法来配置bean --> 4 <bean id="car2" factory-bean="carFactory" factory-method="getCar"> 5 <constructor-arg value="ford"></constructor-arg> 6 </bean>
用FactoryBean配置bean
1 //自定义的FactoryBean需要实现提供的接口 2 public class CarFactoryBean implements FactoryBean<Car> { 3 4 private String name; 5 public void setName(String name) { 6 this.name = name; 7 } 8 9 @Override 10 public Car getObject() throws Exception { 11 // TODO Auto-generated method stub 12 return new Car(name,5000,500); 13 } 14 15 @Override 16 public Class<?> getObjectType() { 17 // TODO Auto-generated method stub 18 return Car.class; 19 } 20 21 @Override 22 public boolean isSingleton() { 23 // TODO Auto-generated method stub 24 return true; 25 } 26 27 28 }
1 <!-- 2 通过FactoryBean来配置bean的实例 3 class=指向FactoryBean的全类名 4 property=配置FactoryBean的属性 5 6 但实际返回的实例确是FactoryBean的getObject方法返回的实例 7 --> 8 <bean id="car" class="com.text.CarFactoryBean"> 9 <property name="name" value="bmw"></property> 10 </bean>
基于注解的方式配置bean,装配bean的属性
组件扫描:spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
1. @Component 基本注解
2. @Respository 持久层
3. @Service 业务层
4. @Controller 表现层
可混用,ioc容器分辨不了,不过建议按层使用,value属性可标示beanName
可增加属性resource-pattern指定扫描的资源。如repository/*.class
可增加子节点
<context:exclude-filter type="annotation" expression=""/> 排除
<context:include-filter type="annotation" expression=""/> 包含(在use-default-filters【不使用默认注解】为false时使用)
expression中可填入如org.springframework.stereotype.Repository等包名
1 <!-- 指定ioc容器扫描的包 --> 2 <context:component-scan base-package="com.rep"></context:component-scan>
实例:autowire自动装配具有兼容类型的单个bean属性
@Controller public class UserController { @Autowire private UserService userService; public void controller() { System.out.println("controller"); userService.add(); } }
@Service public class UserService { public void add() { System.out.println("add"); } }
此时,就可以打印
controller
add
写到这里,突然产生了一个疑问,注解形式和xml形式是如何转化的
重新写了相同作用的xml
1 <bean id="userController" class="com.rep.UserController" > 2 <property name="userService" ref="userService"></property> 3 </bean> 4 5 <bean id="userService" class="com.rep.UserService"></bean>
在userController中的userService变量需要加上setter方法
运行得出相同结论。然后又产生一个问题,之前为啥用bean来着。。
如果不用bean呢?
1 private UserService userService = new UserService(); 2 3 public void controller() { 4 System.out.println("controller"); 5 userService.add(); 6 }
1 UserController userController = new UserController(); 2 //(UserController)ctx.getBean("userController"); 3 userController.controller();
写完对比后,就发现:用bean的原因是为了减少耦合,也就是Controller和Service之间不会产生关系,如果不用bean,Controller中需要new一个Service。而在用spring后,所有的bean都交给ioc容器管理,如果你有需要,跟ioc容器getBean即可。
言归正传,autowire可以有一个属性值required,当为false时,即使bean不存在,也不抛异常,而是允许不被设置。
当匹配的bean有两个或多个时,会抛异常expected single matching bean but found 2
解决方法:(以Service为接口,UserService和OtherService作为实现为例
在Controller中定义接口变量service)
1. 在UserService或者OtherService类上添加@Service("service"),value值为接口变量
2. 在autowired下方加入@Qualifier("otherService"),值为所装配的bean
1 @Autowired 2 @Qualifier("otherService") 3 private Service service;
3. 在参数前加Qualifier,且autowired在setter方法前
1 private Service service; 2 @Autowired 3 public void setService(@Qualifier("otherService")Service service) { 4 this.service = service; 5 }
autowired注解放在
1. 数组类型属性上,spring会把所有匹配的bean进行自动装配
1 @Autowired 2 private Service[] service; 3 4 public void controller() { 5 System.out.println("controller"); 6 service[1].add(); 7 }
2. 集合属性上,spring读取该集合的类型信息,然后自动装配所有与之兼容的bean
1 @Autowired 2 private List<Service> service; 3 4 public void controller() { 5 System.out.println("controller"); 6 service.get(0).add(); 7 }
3. 在map上,若map的键值为String,spring将自动装配与map值类型兼容的bean,此时bean的名称作为键值
1 @Autowired 2 private Map<String,Service> service; 3 4 public void controller() { 5 System.out.println("controller"); 6 service.get("userService").add(); 7 }
泛型依赖注入
public class BaseRepository<T> { }
@Repository public class UserRepository extends BaseRepository<User>{ }
public class BaseService<T> { @Autowired protected BaseRepository<T> repository; public void add() { System.out.println("add"); System.out.println(repository); } }
@Service public class UserService extends BaseService<User>{ }
此时,在main方法中
UserService userService = (UserService)ctx.getBean("userService");
userService.add();
打印结果为
add
com.di.UserRepository@e5a13
即Service父类装配Repository父类,且方法中用的是Repository父类类型变量,当Service子类调用父类方法时,调用的是Repository子类

浙公网安备 33010602011771号