IOC(控制反转)
概述
IOC:(Inversion Of Control):控制反转
控制:资源的获取方式
-
主动式:需要什么资源都自己创建
public class HelloWorld{
BookService bs = new BookService();
bs.addBook();
}
-
被动式:资源的统一交给容器管理,需要的资源即从容器中获取
public class HelloWorld{
BookService bs;
bs.addBook();
}
容器:管理所有的组件(有功能的类);若BookServlet受容器管理,BookService也受容器管理,容器就可以自动探查组件之间的引用关系,创建BookService对象并赋值给BookServlet
DI(Dependency Injection)依赖注入:容器可以探查出组件之间的引用关系,通过反射将创建好对象注入到对应的组件中
步骤
-
导包
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
commons-logging-1.1.1.jar -
写配置文件
创建一个Spring XML Config File,这个文件中集合了Spring的ioc容器管理的所有组件
<!--配置User对象创建-->
<bean id="user" class="com.th1024.bean.User">
<!--set方法注入属性-->
<!--使用property完成属性注入
name:类中属性名称
value:向属性注入的值
-->
<property name="name" value="三上悠亚"></property>
<property name="gender" value="女"></property>
</bean>
- 测试
@Test
public void test1(){
//1. 加载Spring配置文件,获得ioc容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.test();
}
ApplicationContext接口
实验(基于xml配置方式)
- 使用set方法注入属性
<!--配置User对象创建-->
<bean id="user" class="com.th1024.bean.User">
<!--set方法注入属性-->
<!--使用property完成属性注入
name:类中属性名称
value:向属性注入的值
-->
<property name="name" value="三上悠亚"></property>
<property name="gender" value="女"></property>
</bean>
- 有参构造器注入属性
<bean id="user" class="com.th1024.bean.User">
<!--有参构造器注入属性-->
<constructor-arg name="name" value="枫花恋"></constructor-arg>
<constructor-arg name="gender" value="女"></constructor-arg>
<!--属性值包含特殊符号-->
<property name="city">
<value><![CDATA[<<东京>>]]></value>
</property>
</bean>
- 注入属性-外部Bean
userService类中包含userDao属性
<!--外部bean-->
<bean id="userService" class="com.th1024.service.UserService">
<!--向UserDAO对象注入属性值-->
<property name="dao" ref="userDAOImpl"></property>
</bean>
<bean id="userDAOImpl" class="com.th1024.dao.UserDAOImpl"></bean>
- 注入属性-内部Bean
员工类和部门类,一个部门可以有多个员工,一个员工属于一个部门
<!--内部bean-->
<bean id="emp" class="com.th1024.bean.Emp">
<!--设置两个普通属性-->
<property name="name" value="桥本有菜"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.th1024.bean.Dept">
<property name="name" value="F社"></property>
</bean>
</property>
</bean>
级联赋值
第一种写法
<bean id="emp" class="com.th1024.bean.Emp">
<!--设置两个普通属性-->
<property name="name" value="桥本有菜"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.th1024.bean.Dept">
<property name="name" value="F社"></property>
</bean>
第二种写法
生成dept的get方法
public Dept getDept() {
return dept;
}
<bean id="emp" class="com.th1024.bean.Emp">
<!--设置两个普通属性-->
<property name="name" value="桥本有菜"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept" ref="dept"></property>
<property name="dept.name" value="F社"></property>
</bean>
<bean id="dept" class="com.th1024.bean.Dept">
<property name="name" value="S1"></property>
</bean>
- 注入集合属性
public class Stu {
private String[] courses;
private List<String> list1;
private List<Course> list2;
private Map<String,String> maps;
private Set<String> sets;
<bean id="stu" class="com.th1024.bean.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>Java</value>
<value>C++</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list1">
<list>
<value>Java从入门到入土</value>
<value>C++从入门到放弃</value>
</list>
</property>
<!--map类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--set类型属性注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
<!--list集合注入对象-->
<property name="list2">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
<bean id="course1" class="com.th1024.bean.Course">
<property name="name" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.th1024.bean.Course">
<property name="name" value="MyBatis框架"></property>
</bean>
uitl标签提取list集合并注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--提取list集合类型属性注入-->
<util:list id="BookList">
<value>Java从入门到放弃</value>
<value>C++从入门到入土</value>
</util:list>
<!--提取list集合类型属性注入使用-->
<property name="list1" ref="BookList"></property>
实验(基于注解方式)
-
导包:spring-aop-5.2.6.RELEASE.jar
-
开启组件扫描,依赖context名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.th1024"></context:component-scan>
</beans>
- 创建类,在类上添加创建对象注解
以下四个注解都能快速将bean加入到ioc容器中
@Controller:控制器,推荐给控制层的组件(servlet包下)添加此注解
@Service:业务逻辑,推荐给业务逻辑层的组件(service包下)添加此注解
@Repository:仓库,推荐给数据库层的组件(dao包下)添加此注解
@Component:组件,给不属于以上几层的组件添加此注解
此种分类方法目的是便于程序员进行后期维护,Spring框架并不会验证添加这些注解的组件是否真的属于业务逻辑层或控制层
//value属性值可以省略不写,默认是类名首字母小写
@Service(value = "userService") //<bean id="userService" class="..."></bean>
public class UserService {
- 基于注解方式实现属性注入
@Autowired:根据属性类型进行自动装配(Spring定义的注解,功能强大)
@Qualifier:根据名称进行注入,与@Autowired搭配使用
@Resource:可以根据类型注入,也可以根据名称注入(Java的标准,扩展性更强)
@Value:注入普通类型属性
//value属性值可以省略不写,默认是类名首字母小写
@Service(value = "userService") //<bean id="userService" class="..."></bean>
public class UserService {
//添加注入属性注解
@Autowired //根据类型进行注入
/*
首先按照类型去容器中寻找对应的组件
找到一个,直接赋值
没找到,抛异常
找到多个(多个类存在继承关系),按照变量名作为id继续匹配
可以使用@Qualifier(value = "UserDAOImpl1")根据指定的id寻找
@Autowired可以标注在构造器上、方法上、参数上、属性上、注解上
@Qualifier可以标注在方法上、参数上、属性上、注解上
@Resource拓展性更强,此注解为Java的标准--javax.annotation.Resource
*/
// @Qualifier(value = "UserDAOImpl1")//根据指定的名称进行注入
// @Resource(name = "UserDAOImpl1")//既可以根据类型进行注入,也可以根据名称进行注入
private UserDAO dao;
@Value(value = "test")
private String str;
public void setDao(UserDAO dao){
this.dao = dao;
}
public void test(){
System.out.println("service-test");
dao.test();
System.out.println(str);
}
public void test1(){
System.out.println("service-test1");
}
}
- 完全注解开发
创建配置类代替xml配置文件
@Configuration //作为配置类,代替xml文件
@ComponentScan(value = "com.th1024")
public class SpringConfig {
}
泛型依赖注入
创建一个基础的web项目环境,测试泛型依赖注入
泛型依赖注入,注入一个组件的时候,泛型同样也是参考标准
测试
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = applicationContext.getBean(BookService.class);
UserService userService = applicationContext.getBean(UserService.class);
bookService.save();
userService.save();
}
打印结果
自动注入的dao:com.th1024.dao.BookDao@38c5cc4c
BookDao保存图书
自动注入的dao:com.th1024.dao.UserDao@37918c79
UserDao保存用户