IOC底层实现与结论
IOC,指的是控制反转,以往我们要使用一个类,需要手动去new,使用spring框架后,这一步就可以交给spring框架处理,相当于把对象的控制权交给了spring框架,所以叫控制反转;
IOC的底层实现其实很简单,创建一个BeanFactory,用xml解析器获取xml中配置好的类,再利用反射新建一个类,以下是代码实现;
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
public class User {
public void add(){
System.out.println("add方法执行了....");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.springDemo.User"/>
</beans>
public class SpringDemo {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
结论
- 实现IOC容器有两个接口
- BeanFactory : 只有在获取bean时才会创建对象,不推荐使用;
- ApplicationContext : 是前者的子接口,功能更强大,在加载配置文件时就已经创建完所有对象,加快了响应时间,推荐使用;
Bean的依赖注入
依赖注入又称DI,作用就是给bean注入属性
基础依赖注入(xml方式)
public class User {
private String name;
private String age;
public void setName(String name) {
this.name = name;
}
public void setAge(String age) {
this.age = age;
}
}
<bean id="user" class="com.springDemo.User">
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
</bean>
public class User {
private String name;
private String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
}
<bean id="user" class="com.springDemo.User">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
注入外部bean
public interface UserDao {
public void update();
}
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDao update....");
}
}
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
<bean id="userService" class="com.example.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>
注入内部bean
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
public class Emp {
private String ename;
private String gender;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
<bean id="emp" class="com.example.domain.Emp">
<property name="ename" value="张三"></property>
<property name="gender" value="男"></property>
<property name="dept">
<bean id="dept" class="com.example.domain.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
</bean>
注入集合类型属性
public class Student {
private String[] arr;
private List<String> list;
private Map<String,String> map;
public void setArr(String[] arr) {
this.arr = arr;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
<bean id="student" class="com.collection.Student">
<property name="arr">
<array>
<value>语文</value>
<value>数学</value>
</array>
</property>
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
</bean>
Bean标签的基本配置
id:唯一标识,可以取任意名称,但必须唯一; class:实现类的全限定名称;
scope:对象的作用范围;
当scope的的取值范围为:singleton Bean的实例化个数为:1个 Bean的实例化时机:当加载Spring配置文件时,实例化配置中的Bean Bean的生命周期:
- 对象创建,当应用加载,创建容器时,对象就被创建了;
- 对象运行,只要容器在,对象一直活着;
- 对象销毁,随着容器销毁一起销毁;
当scope的的取值范围为:prototype Bean的实例化个数为:多个 Bean的实例化时机:每当调用getBean()方法时都会实例化一次Bean; Bean的生命周期:
- 对象创建,调用getBean()方法时都会实例化一次Bean;
- 对象运行,只要对象在使用中,就会一直存活;
- 对象销毁,长时间未使用会被垃圾回收器回收;
Bean生命周期配置;
- init-method:指定类中的初始化方法的名称;
- destroy-method:指定类中的销毁方法名称;
基于注解方式实现对象创建
- @Conponent
- @Service
- @Controller
- @Repository
这四个注解功能都是一样的,都是为了创建对象,不同的层放不同的注解方便辨识;
组件扫描配置
使用注解必须写好组件扫描配置,以下介绍几种常用配置;
<?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: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.demo"/>
</beans>
@Component("userDao")
public class UserDao {
public void add(){
System.out.println("userDao add...");
}
}
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
userDao.add();
}
<context:component-scan base-package="com.demo" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:component-scan base-package="com.demo" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
基于注解方式实现属性注入
根据属性类型进行自动注入
<context:component-scan base-package="com.demo" />
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDao add ...");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void add(){
System.out.println("service add...");
userDao.add();
}
}
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
根据属性名称进行自动注入 需要跟@Autowired一起使用,一个接口可以有多个实现类,不知道用哪个时,可以使用@Qualifier指定
@Repository(value = "userDaoA")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDao add ...");
}
}
@Service
public class UserService {
@Autowired
@Qualifier(value = "userDaoA")
private UserDao userDao;
}
可以根据类型注入也可以根据名称注入,因为是javax扩展包的注解,所以spring官方不建议使用
@Repository(value = "userDaoA")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("UserDao add ...");
}
}
@Service
public class UserService {
@Resource(name = "userDaoA")
private UserDao userDao;
private UserDao userDao;
}
注入普通类型属性
@Value("abc")
private String name;
完全注解开发
就是指删除xml配置,创建一个SpringConfig对象来代替xml配置,同时测试类的ApplicationContext实现类也需要变更为AnnotationConfigApplicationContext,实际开发中一般使用spring boot方式;
@Configuration
@ComponentScan(basePackages = {"com.demo"})
public class SpringConfig {
}
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
|