不管是注解注入还是在xml文件中配置Bean注入的本质:利用反射创建实例对象。
一、静态工厂 | | 实例工厂、Spring的工厂类
1、静态工厂 | | 实例工厂
静态工厂:只需要直接调用工厂类的静态方法,不需要new对象。
public class BeanStaticFactory {
public static Car getBean() {
Car car = new Car("雷克萨斯", 110);
return car;
}
}
实例工厂:需要new对象,再用对象调方法。
public class BeanInstanceFactory {
public Car getBean() {
Car car = new Car("本田", 90);
return car;
}
}
XML配置:
<bean class="cj.factory.BeanStaticFactory" id="f1" factory-method="getBean" scope="prototype"></bean>
测试结果(以静态工厂举例,和实例工厂差不多):
XML配置(默认是单例对象):
<bean class="cj.factory.BeanStaticFactory" id="f1" factory-method="getBean"></bean>
测试结果(以静态工厂举例,和实例工厂差不多):
总结:自己写的静态工厂和实例工厂,在容器中初始化的时机和之前的bean一样。假如是单例对象,那么在容器创建前就初始化进IOC容器;多例对象则容器创建前不会进入容器,当该对象被获取的时候才进入Spring的容器中。
2、Spring的工厂类
spring的工厂类:实现了FactoryBean<T>
的接口。
public class MyFactoryBean implements FactoryBean<Car> {
public Car getObject() throws Exception {
Car car = new Car("福特", 100);
return car;
//返回值不能是空, 相当于这个方法代理了getBean方法。
//如果返回值为空了, getBean就获取不到对象了。
}
public Class<?> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return true;
}
}
isSingleton函数返回为true测试结果:
isSingleton函数返回为false测试结果:
总结:实现了FactoryBean的Bean,不管是单例还是多例,都是在容器创建后才放进Spring的IOC容器中的。
3、BeanFactory和FactoryBean的区别
BeanFactory直译过来就是Bean的工厂,他是一个工厂类,在Spring容器中所有的Bean都是由BeanFactory(IOC容器)管理的。 但是FactoryBean还是个Bean,不过是个特殊的工厂Bean。
二、后置处理器
偏源码的解释:
ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器。
bean的后置处理器和bean标签的init-method属性执行顺序为:
1、执行BeanPostProcessor接口中的before方法(postProcessBeforeInitialization—初始化前方法),
2、后执行init-method方法,
3、最后执行after方法(postProcessAfterInitialization—初始化后方法)。
一些Spring AOP的底层处理也是通过实现bean后置处理器来执行代理包装逻辑。
我们定义一个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理。
三、注解与自动装配
1、注解
注解注入的本质:利用反射创建实例对象。
① 注解注入
注解注入:@Repository、@Service、@Controller、@Component
持久层用的Repository注解、业务层用的Service注解、控制层用的Controller注解。
上面三个注解都实现了Component注解接口。所以扫描包的时候指定注解配置,且注解类型是Component的时候,上述注解都会添加到Spring的IOC容器中
@Component
public class TestDemoZhujie {
}
单单通过注解注入某个Bean到IOC容器后,该Bean默认的id是原来首字母改为小写的类名。也可以通过注解的value属性修改该id,当注解中只写了value属性的时候,value可以省略不写。
② 修改单例、多例
默认是单例对象,通过@Scope(value = "prototype")
修改为多例对象。
2、自动装配
自动装配:只能装自定义的对象。自动为这个Bean装配成员变量,前提是装配的变量已经在容器中了。且必须要有对应成员变量的set和get方法,否则注入为空。
① XML配置
<bean class="cj.entity.Car" id="car3" init-method="init" destroy-method="destroy">
<property name="carSpeed" value="666"></property>
<property name="carName" value="奔驰"></property>
</bean>
<bean class="cj.entity.Person" id="p1" autowire="byName"></bean>
测试结果:
结果表明自动装配成功。
② 注解配置
@Controller
public class UserServlet {
@Autowired
private UserService userService;
public void add() {
userService.add();
}
@Autowired
public void run(@Qualifier("userDao2") UserDao userDao, UserService userService) {
System.out.println("66666666" + userDao + "---" + userService);
}
}
@Autowired(注在成员变量上):自动以成员变量的类型去容器中寻找Bean,找不到就报错。如果匹配多个,则按照当前Bean的成员变量的名字作为id去Spring的IOC容器中寻找Bean,没找到就报错。Autowired注解一出场,就必须找到,可以通过指定属性@Autowired(required = false)
找不到就为null。不需要set和get方法就可以成功注入,只要装配的变量在Spring的IOC容器中即可。
@Autowired(注在成员方法上):将从容器中自动装配方法参数。并且这个方法也会在创建Bean的时候自动运行。
@Qualifier:一般和Autowired注解连用,当默认的找不到的时候,指定寻找的Bean的id。也可以注在方法参数上。