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子类  

posted @ 2016-04-11 17:55  七彩蝶  阅读(152)  评论(0)    收藏  举报