上篇文章简单介绍了IOC, 本文则是重点讲述如何使用Spring5里的IOC进行Bean管理, 有两种方式, 分别是基于xml文件和注解, 我们都会一一讲到。
IOC容器的底层就是对象工厂
Spring提供了IOC容器的两种实现方式(两个接口):
BeanFactory: IOC容器基本实现, 是Spring内部使用的接口, 不提供给开发人员使用, 加载文件的时候不会船舰对象, 在获取对象的时候才会创建对象。
ApplicationContext: BeanFactory接口的子接口, 提供更多更强大的功能, 加载配置文件的时候就会把在配置文件中配置好的对象进行创建。
ApplicationContext的四个常用实现类:
Spring提供了三种方式来依赖注入,有构造方法注入, setter方法注入以及接口注入。其中Spring以往推荐使用Setter的方法现在改成推荐构造方法注入。使用构造方法注入需要注意的一点就是要避免循环依赖。所谓的循环依赖指的就是在A对象的构造方法中Spring要注入B,而在B对象中Spring要注入A。这个时候会形成一个闭环因为Spring不知道该先注入哪一个接着会抛出异常。而Spring建议的处理方式是说如果遇到这种情况的话就改用Setter方式注入。
<!--配置User对象的创建--> <bean id="user" class="com.ayu.User"></bean>
使用set方法进行注入
在bean标签内使用property标签完成属性注入:
name: 类中属性名称
value: 属性中注入的值
<!--使用set方法进行参数注入--> <bean id="user1" class="com.ayu.User"> <property name="name" value="Tom"></property> <property name="age" value="11"></property> </bean>
使用有参构造器进行注入
在bean标签内使用constructor-arg标签完成属性注入:
name: 类中属性名称
value: 属性中注入的值
<!--使用有参构造方法进行参数注入--> <bean id="user2" class="com.ayu.User"> <constructor-arg name="name" value="Jerry"></constructor-arg> <constructor-arg name="age" value="11"></constructor-arg> </bean>
字面量
null值
使用标签
<!--null值--> <property name="name"> <null/> </property>
属性值包含特殊符号
使用CDATA
<!--特殊字符--> <property name="name"> <value> <![CDATA[<<时生>>]]> </value> </property>
注入外部bean
使用ref属性注入外部创建好的bean对象
<!--外部bean--> <bean id="userService" class="com.ayu.service.UserService"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.ayu.dao.UserDao"></bean>
注入内部bean
直接在property标签里创建bean标签
<!--内部bean--> <bean id="emp" class="com.ayu.bean.Emp"> <property name="name" value="张三"></property> <property name="dept"> <bean id="dept" class="com.ayu.bean.Dept"> <property name="deptNo" value="101"></property> </bean> </property> </bean>
级联赋值
对属性里的bean对象的属性进行赋值操作
<!--级联赋值--> <bean id="emp1" class="com.ayu.bean.Emp"> <property name="name" value="张三"></property> <property name="dept" ref="dept1"></property> <property name="dept.deptNo" value="102"></property> </bean> <bean id="dept1" class="com.ayu.bean.Dept"></bean>
<bean id="stu" class="com.ayu.collection.Student"> <property name="courses"> <array> <value>语文</value> <value>数学</value> <value>英语</value> </array> </property> <property name="list"> <list> <value>java</value> <value>go</value> <value>c++</value> </list> </property> <property name="map"> <map> <entry key="java" value="88"></entry> <entry key="c++" value="78"></entry> </map> </property> <property name="set"> <set> <value>MySQL</value> <value>SQLServer</value> </set> </property> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property> </bean> <bean id="course1" class="com.ayu.collection.Course"> <property name="name" value="Spring5"></property> </bean> <bean id="course2" class="com.ayu.collection.Course"> <property name="name" value="SpringMVC"></property> </bean>
<!-- 配置命名空间 --> 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-2.0.xsd"> <!-- 使用util标签来配置共享的bean--> <util:list id="bookList"> <value>大话数据结构</value> <value>程序是怎样跑起来的</value> <value>操作系统导论</value> </util:list> <bean id="book" class="com.ayu.collection.Book"> <property name="list" ref="bookList"></property> </bean>
<!-- 配置命名空间 --> xmlns:p="http://www.springframework.org/schema/p" <!--使用p命名空间来配置bean--> <bean id="user" class="com.ayu.User" p:name="Tom" p:age="11"></bean>
Spring中可以使用scope属性来配置bean的作用域:
<!--设置scope属性--> <bean id="user" class="com.ayu.User" scope="singleton"></bean>
创建一个测试用的Order类:
public class Order { private String name; public Order() { System.out.println("1.无参构造"); } public void setName(String name) { this.name = name; System.out.println("2.set方法"); } public void initMethod() { System.out.println("3.初始化方法"); } public void destroyMethod() { System.out.println("5.销毁方法"); } @Test public void testOrder() { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Order order = context.getBean("order", Order.class); System.out.println("4.获取到bean对象"); System.out.println(order); ((ClassPathXmlApplicationContext) context).close(); } }
配置文件:
<bean id="order" class="com.ayu.bean.Order" init-method="initMethod" destroy-method="destroyMethod"> <property name="name" value="手机"></property> </bean>
测试结果:
1.无参构造
2.set方法
3.初始化方法
4.获取到bean对象
com.ayu.bean.Order@69b0fd6f
5.销毁方法
使用后置处理器后的生命周期:
创建一个后置处理器类实现BeanPostProcessor接口:
public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之前"); return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("初始化之后"); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } }
在配置文件中配置BeanPostProcessor:
<bean id="myBeanPost" class="com.ayu.bean.MyBeanPost"></bean>
测试结果:
1.无参构造
2.set方法
初始化之前
3.初始化方法
初始化之后
4.获取到bean对象
com.ayu.bean.Order@66d1af89
5.销毁方法
bean标签的autowire属性实现自动装配, autowire有两个常用的值:
byName: 根据属性名称注入, 注入值bean的id值和类属性值名称需一样
<bean id="emp" class="com.ayu.autowrite.Emp" autowire="byName"> <!--<property name="dept" ref="dept"></property>--> </bean> <bean id="dept" class="com.ayu.autowrite.Dept"></bean>
byType: 根据属性类型注入
<bean id="emp" class="com.ayu.autowrite.Emp" autowire="byType"> <!--<property name="dept" ref="dept"></property>--> </bean> <bean id="dept" class="com.ayu.autowrite.Dept"></bean>
注: 通过byType自动装配,已配置的bean中有多个该类型的bean时会报错
下面四个注解功能是一样的,都可以用来创建 bean 实例
开启组件扫描:
如果扫面多个包, 可以用逗号隔开, 或是扫描包的上层目录
<context:component-scan base-package="com.ayu"></context:component-scan>
创建类, 在类上添加对象注解
//value属性可以不写, 会默认类名首字母小写为value的值 @Repository(value="userDao") public class UserDaoImpl implements UserDao{ @Override public void hello() { System.out.println("hello dao"); } }
<!--示例一:use-default-filters表示现在不使用默认filter,自己配置filter content:include-filter 设置扫面那些内容--> <content:component-scan base-package="com.ayu" use-default-filters="false"> <content:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </content:component-scan> <!--示例二:下面配置扫面包所有内容 content:exclude-filter 设置哪些内容不进行扫描--> <content:component-scan base-package="com.ayu" use-default-filters="false"> <content:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </content:component-scan>
@Autowired: 根据属性类型进行自动装配
@Service public class UserService { //不需要set方法 @Autowired private UserDao userDaO; public void hello() { System.out.println("hello service"); userDaO.hello(); } }
@Qualifier: 根据属性名称进行注入, 通常和@Autowired一起使用
@Service public class UserService { //不需要set方法 //区别同一接口下多个实现类 @Autowired @Qualifier(value="userDaoImpl") private UserDao userDaO; public void hello() { System.out.println("hello service"); userDaO.hello(); } }
@Resource: 可以根据类型注入,也可以根据名称注入(这个注解是JDK提供的)
@Resource(value="userDaoImpl") private UserDao userDaO;
@Value: 注入普通类型属性
@Value(value = "service") private String name;
创建配置类, 代替xml配置文件
@Configuration @ComponentScan(basePackages = {"com.ayu"}) public class SpringConfig {}
此时应使用AnnotationConfigApplicationContext这个实现类:
//AnnotationConfigApplicationContext需要将配置类传给它 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); userService.hello();
我的个人主页: www.ayu.link
本文连接: ┏ (゜ω゜)=☞