Spring IOC
1.1 概述
控制反转是一个比较抽象的概念,对于初学者不好理解,我们举例说明。在实际生活中,人们要用到一样东西时,人们的基本想法是找到东西,比如想喝杯橙汁,在没有饮品店的日子里,最直观的做法是,要买果汁机、橙子,准备开水。请注意这是你自己" 主动"创造的过程,也就是一杯橙汁需要主动创造。然而到了今时今日,由于饮品店的盛行, 已经没有必要自己去榨橙汁了。想喝橙汁的想法一出现,第一个想法是找到饮品店的联系方式,通过电话、微信等渠道描述你的需要、地址、联系方式等,下订单等待,过会就会有人送上橙汁了。请注意你并没有"主动"创造橙汁,也就是橙汁是由饮品店创造的,而不是你,但是也完全达到了你的要求。
1.2 控制反转
控制反转是一种通过描述(在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了
1.3 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是新的
1.4 通过构造注入
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;
}
1.5 工厂方法注入(静态工厂、非静态工厂)
1.6 注入集合
<bean id="people6" class="entity.People">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
<property name="hobbies"> 类那边 需 new一个 ArrayList
<list>
<value>唱歌</value>
<value>跳舞</value>
</list>
</property>
<property name="loves"> 类那边 需 new一个 HashSet
<set>
<value>唱歌2</value>
<value>跳舞2</value>
</set>
</property>
<property name="works"> 类那边 需 new一个 HashMap
<map>
<entry>
<key><value>上午</value></key>
<value>写代码</value>
</entry>
<entry>
<key><value>下午</value></key>
<value>测试代码</value>
</entry>
</map>
</property>
<property name="addresses"> 类那边 需 new一个 Properties
<props>
<prop key="address1">aaaaa</prop>
<prop key="address2">bbbbb</prop>
</props>
</property>
</bean>
1.7 通过注解装配bean
1.7.1 @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"})
1.7.2 @Autowired
@Autowired
private Role role;
也可以在setter方法上注解
@Autowired
public void setRole(Role role) {
this.role = role;
}
注意:
@Autowired默认情况下,spring会认为一定要找到对应的bean注入这个字段,否则报错,但有时候可有可无,则需
@Autowired(required = false)
1.7.3 @Primary和@Qualifier
当下面这个UserDao有多个实现类的时候,spring就不知道该注入哪个实现类了就会报错
@Autowired
private UserDao userDao;
那么需要这么解决,表示优先注入这个实现类
@Primary
public class UserDaoImpl2 implements UserDao{
}
或者
@Autowired
@Qualifier("userDaoImpl2")
private UserDao userDao;
在构造中使用@Autowired
public UserBizImpl(@Autowired UserDao userDao) {
this.userDao = userDao;
}(编译过不去,原因未明)