SpringIOC 实现原理

什么是SpringIOC
spring ioc指的是控制反转,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。交由Spring容器统一进行管理,从而实现松耦合。
控制反转是一种通过描述(在Java中可以是xml或注解)并通过第三方去产生或者获取对象的方式
SpringIOC容器的设计主要是基于BeanFactory和AppilicationContext两个接口
BeanFactory是Spring定义的最底层的接口,AppilicationContext是BeanFactory的子接口之一
BeanFactory中定义了多个抽象方法
getBean 用于获取配置给SpringIOC容器的bean
isSingle 单例
isPrototype 多例
getAliases 获取别名
ApplicationContext的间接实现类ClassPathXmlApplicationContext

spring-config.xml:

<beans …>
<bean id="userDaoImpl" class="dao.impl.UserDaoImpl"></bean>
<bean id="userBizImpl" class="biz.impl.UserBizImpl" scope="singleton">
		<property name="bName" value="bName1"></property>
		<property name="bNum" value="1"></property>
		<property name="userDao" ref="userDaoImpl"></property>(注入自定义类)
</bean>
</beans>

这里定义了两个bean,这样SpringIOC容器在初始化的时候就能找到他们,然后使用ClassPathXmlApplicationContext就可以将其初始化。

ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml "});
UserBiz userBiz  =  (UserBiz) ac.getBean("userBizImpl");

Spring bean要先初始化,才会进行依赖注入
初始化的3个步骤:
(1) resource定位,通过xml或者注解的方式定位
(2) beandefinition的载入,spring通过配置获取pojo(用于生成实例)
(3) beandefinition的注册,把载入的pojo往springIOC容器中注册
这样就可以得到springIOC容器的bean了。

setter注入
spring-config.xml文件:

<beans …>
<bean id="userDaoImpl" class="dao.impl.UserDaoImpl"></bean>
<bean id="userBizImpl" class="biz.impl.UserBizImpl" scope="singleton">
		<property name="bName" value="bName1"></property>
		<property name="bNum" value="1"></property>
		<property name="userDao" ref="userDaoImpl"></property>(注入自定义类)
</bean>
</beans>

注意:配bean时候,若没有写id,则spring将会采用“全限定名#{number}”的格式生成编号,如:
biz.impl.UserBizImpl #1、biz.impl.UserBizImpl#2

userBizImpl.java文件:

private String bName;
private int bNum;
private UserDao userDao;
/*** getter setter  ***/

Test.java文件:

ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"spring-config.xml "});
UserBiz userBiz  =  (UserBiz) ac.getBean("userBizImpl");

注意:
scope属性表示bean的作用域 不写默认是单例模式singleton,每次实例化bean都是同一个bean
prototype多例 每次实例化bean都是新的,
request 每次请求时实例化bean是新的
session 浏览器打开关闭之间实例化bean是新的
global session 相当于 application 服务器打开关闭之间实例化bean是新的

构造注入
application.xml文件:

<bean id="userDaoImpl" class="dao.impl.UserDaoImpl"></bean>
<bean id="userBizImpl3" class="biz.impl.UserBizImpl" scope="singleton">
		<constructor-arg index="0" value="bName3"></constructor-arg>
		<constructor-arg index="1" value="3"></constructor-arg>
		<constructor-arg index="2" ref="userDaoImpl"></constructor-arg>
</bean>

userBizImpl.java文件,需要有对应的构造器:

//需要有对应的构造器
public UserBizImpl(String bName, int bNum,UserDao userDao) {
		super();
		this.bName = bName;
		this.bNum = bNum;
		this.userDao = userDao;
}

工厂方法注入(静态工厂、非静态工厂)

通过注解装配bean
@Component
Role.java文件:

@Component(value="role")
public class Role {
	@Value("123")//这里 id是long型 spring注入时候会为其转型
	private Long id;
	@Value("role_name_1")
	private String roleName;
	@Value("note1")
	private String note;
	}

注意:@Component(value=“role”)//相当于xml方式,定义bean中的id不写@Component 默认为类名并且首字母小写

PojoConfig.java文件:

@Configuration
@ComponentScan
public class PojoConfig {
}

Test.java文件:

ApplicationContext ac = new AnnotationConfigApplicationContext(PojoConfig.class);
Role role = (Role) ac.getBean("role");//也可以这么获取Role role = ac.getBean(Role.class);
System.out.println(role.getId());
打印结果 123

注意:
@ComponentScan只会扫描所在包的Java类,若需要指定哪些类则需
@ComponentScan(basePackageClasses = {Role.class,User.class} )
或者
@ComponentScan(basePackages = {“entity.Role”,“biz.impl”})

@Autowired

@Autowired
private Role role;

也可以在setter方法上注解:

@Autowired
public void setRole(Role role) {
	this.role = role;
}

注意:
@Autowired默认情况下,spring会认为一定要找到对应的bean注入这个字段,否则报错,但有时候可有可无,则需
@Autowired(required = false)

@Primary和@Qualifier
当下面这个UserDao有多个实现类的时候,spring就不知道该注入哪个实现类了就会报错

@Autowired
private UserDao userDao;

那么需要这么解决,表示优先注入这个实现类

@Primary
public class UserDaoImpl2 implements UserDao{
}

或者

@Autowired
@Qualifier("userDaoImpl2")
private UserDao  userDao;

版权声明:本文为weixin_39672065原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。