Spring-IOC
Spring-IOC
cmyangIOC:控制反转,将创建对象的操作交给Spring处理,要使用某个对象,只需要从Spring容器中获取,主要目的是为了降低耦合
1. 示例
创建一个maven项目
在pom文件中引入spring的依赖spring-context,context依赖了spring的4大核心包,spring-core,spring-beans,spring-core,spring-expression
1 | <dependency> |
- 编写一个类Hello
1 | package cn.aacopy.learn.spring; |
- 编写一个配置bean的XML文件bean.xml放在classpath路径下
1 |
|
- 在main方法中获取hello对象,并调用hello方法
1 | public static void main( String[] args ) { |
2. 原理
通过xml解析,工厂模式,反射来实现
A类中引用B类的对象,最原始的方式是在A类中new一个B类的对象进行使用,这样B发生改变可能会影响到A类,为了降低耦合度,可以创建一个获取B对象的工厂类,A类需要B类对象时,只需要从工厂类中获取,这样就不需要关系B类是怎么创建的,降低了耦合度。在工厂类中,需要创建类的对象,可以统一通过从配置文件中获取全类名称和初始化参数,通过反射的方式来创建类,避免硬编码,所有需要通过工厂来创建的类,统一写在配置文件中
获取IOC容器的两种方式
BeanFactory和ApplicationContext
1
2
3
4
5
6public static void main( String[] args ) {
BeanFactory applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
Hello hello = applicationContext.getBean(Hello.class);
hello.hello();
}BeanFactory是IOC容器的基础实现,一般在spring内部使用,在加载配置文件的时候不会立即创建对象,在获取的bean对象的时候创建
ApplicationContext是BeanFactory的子接口,提供了更多的功能,在加载配置文件的时候,会立即创建对象
继承关系
Bean管理:(1)创建对象,(2)注入属性
Bean管理的两种方式:(1)基于XML,(2)基于注解
3. 管理Bean
3.1 基于XML方式
<bean id="hello" class="cn.aacopy.learn.spring.Hello"></bean>
- id:bean的唯一标识
- class:类全路径
3.1.1 创建对象
spring创建对象时,默认调用类的无参构造器进行创建
3.1.2 注入属性
注入属性有两种方式,(1)通过调用set方法,(2)通过有参构造器
set方式注入
- 创建一个User对象,包含name,age两个属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26package cn.aacopy.learn.spring;
/**
* @author cmyang
* @date 2022/9/9 22:17
*/
public class User {
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}- 在bean的xml配置文件中配置User,通过property配置,spring可以通过name找到对应的属性,并将value的值赋给属性
1
2
3
4<bean id="user" class="cn.aacopy.learn.spring.User">
<property name="name" value="小七"></property>
<property name="age" value="18"></property>
</bean>- 编写测试类
1
2
3
4
5public static void main( String[] args ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
User user = applicationContext.getBean(User.class);
System.out.println(user); //User{name='小七', age=18}
}有参构造器
- 在上面的User类中添加全参和无参构造器
1
2
3
4
5
6
7public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}- 在bean的xml配置文件中通过constructor-arg指定构造器的参数
1
2
3
4<bean id="user" class="cn.aacopy.learn.spring.User">
<constructor-arg name="name" value="小七"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
3.1.3 特殊值的注入
在XML的配置中,如果要设置对应的值为null,可以使用
<null/>
,例如:<constructor-arg name="name"><null/></constructor-arg>
如果配置的值有特殊符号,可以通过
<![CDATA[]]>
包裹如果需要引用其他bean,需要使用ref属性,例如:
<property name="hello" ref="hello"></property>
注入数组
1 | <property name="arr"> |
- 注入list
1 | <property name="list"> |
- 注入map
1 | <property name="map"> |
3.2 基于注解的方式
3.2.1 创建对象
添加context命名空间
在bean.xml中开启注解扫描,base-package配置扫描的路径
<context:component-scan base-package="cn.aacopy"></context:component-scan>
使用:@Component,@Controller,@Service,@Repository等注解标识为spring容器的bean
- 只扫描固定的注解下的类
1 | <context:component-scan base-package="cn.aacopy" use-default-filters="false"> |
- 排除注解下的类
1 | <context:component-scan base-package="cn.aacopy"> |
3.2.2 属性注入
- @Autowired
- 根据类型进行装配
- 如果同一个类型有多个实现类的bean,需要使用@Qualifier指定需要注入的bean名称
- @Resource
- 根据名称进行装配 (参数name指定bean的名称)
- 也可以根据类型装配
- @Value
- 注入普通类型的值
3.2.3 通过注解方式
- 编写一个配置类来代替bean.xml配置
1 |
|
- 获取容器的方式改为注解方式
1 | public static void main( String[] args ) { |
4. Bean类型
bean有两种类型,一种时普通bean,一种是工厂bean
普通bean
- 返回的就是创建的bean的类型
工厂bean
- 需要实现FactoryBean接口,其中getObject就是返回的bean对象,对象类型可以用泛型定义
1
2
3
4
5
6
7
8
9
10
11public class MyFactoryBean implements FactoryBean<User> {
public User getObject() throws Exception {
return new User();
}
public Class<?> getObjectType() {
return User.class;
}
}1
<bean name="myFactoryBean" class="cn.aacopy.learn.spring.MyFactoryBean"></bean>
1
2
3
4
5public static void main( String[] args ) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
User user = applicationContext.getBean("myFactoryBean", User.class);
System.out.println(user);
}
5. Bean作用域
singleton:单例, 默认值,prototype:多例,request,session,global session
通过scope配置
6. Bean生命周期
生命周期是bean从创建到销毁的过程
- 基本过程
- 通过无参构造器创建bean对象
- 调用set方法设置属性和其他对象
- 调用初始化方法(需要设置初始化方法名)
- 使用bean
- 容器关闭时,调用销毁方法(需要设置销毁方法名)
在第三步初始化方法的前后,可以执行后置处理器,需要实现BeanPostProcessor接口
1 | public class User { |
创建后置处理
1 | public class MyBeanPostProcessor implements BeanPostProcessor { |
注入bean
1 | <bean id = "user" class="cn.aacopy.tools.mytest.spring.User" init-method="init" destroy-method="destroy"> |
执行方法
1 | public static void main(String[] args) { |
执行后的结果:
1 | 调用构造器创建对象 |
7. 自动装配
7.1 通过XML方式
- 在User对象中添加属性private School school;
- 添加School的bean
- 修改User的配置文件进行自动装配,有两种类型,一种是byType,一种是byName
1 | <bean id = "user" class="cn.aacopy.tools.mytest.spring.User" autowire="byName"> |
8. 引入配置文件数据
8.1 通过XML方式
- 添加配置文件:aacopy.properties,放在classpath下面
1 | aacopy.aa=AA |
- 在User对象里设置name,age两个属性,添加set方法
1 | private String name; |
- 配置bean.xml,首先需要用到context命名空间,要在头部引入,导入配置文件,使用${}获取配置文件中的属性
1 |
|