spring_bean三种装配方式
bean装配:spring ioc 容器将bean对象创建好并传递给使用者的过程叫bean的装配
spring ioc 会创建我们在配置文件中配置好的对象,并将对象返回给使用者,spring ioc创建对象的方式有以下三种
1:默认方式,通过构造器来创建
<bean id="自定义id" class="接口的实现类" />2:实例工厂
<bean id="factory" class="工厂类" /> <bean id="自定义id" factory-bean="factory" factory-method="调用的实例化工厂方法" />3:静态工厂
<bean id="自定义id" class="工厂类" factory-method="静态工厂方法" /># 默认方式
该方式spring ioc容器会调用bean(接口实现类)的无参构造方法来创建对象,当创建一个java类后,系统会自动在类中创默认构造函数,当自己创建个构造方法时默认构造函数就会不存在,所以开发者需确保在bean中存在无参构造方法
<!-- 默认方式 --> <bean id="studentService" class="com.doaoao.impl.StudentServiceImpl"/># 实例工厂
1:定义一个工厂类,该类中的方法都是非静态的(方法的返回值为StudentService类型)
package com.doaoao.factory; import com.doaoao.impl.StudentServiceImpl; import com.doaoao.service.StudentService; public class BeanFactory { public StudentService createStudentService(){ return new StudentServiceImpl(); } }2:修改配置文件中的内容(主要为了告诉spirng我们要使用 实例工厂 方法)
<!-- 创建实例工厂配置温江 id 和class --> <bean id="myFactory" class="com.doaoao.factory.BeanFactory" /> <!-- 将上创建的实例工厂 myFactory添加进去,利用实例工厂中的方法 factory-method指定的方法,来创建studentService --> <bean id="studentService" factory-bean="myFactory" factory-method="createStudentService" />其它与之前的相同
# 静态工厂(中的方法都是 static 修饰的)
1:定义一个工厂类,类的中的方法都为静态方法(从该类中来看和实例工厂对比只是多了一个static)
package com.doaoao.factory; import com.doaoao.impl.StudentServiceImpl; import com.doaoao.service.StudentService; public class StaticBeanFactory { public static StudentService createStudentService(){ return new StudentServiceImpl(); } }2:修改配置文件中的内容
<!-- 静态工厂:调用class指定的工厂类的方法 createStudentService 来创建 id 指定的对象--> <bean id="studentService" class="com.doaoao.factory.StaticBeanFactory" factory-method="createStudentService" />## 注:在使用时,一般使用默认方式即可
## bean的作用域
singleton: 单例模式。即在一个Spring ioc容器中,只创建一个对象,默认为单例模式
prototype: 原型模式。即每次使用 getBean 方法获取的同一个bean的实例都是一个新的实例
request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例
session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例(同一个浏览器中产生同一个session)
application:在一个web应用中会产生一个bean实例,就相当于在一个ServletContext中只有该bean的实例
websocket:在一个websocket中会产生一个bean实例
单利模式例子:
1:在StudetnServiceImpl.java中创建一个无参构造方法
package com.doaoao.impl; import com.doaoao.service.StudentService; public class StudentServiceImpl implements StudentService { @Override public void testDao() { System.out.println("Hello World"); } public StudentServiceImpl(){ System.out.println("执行 StudentService的构造方法"); } }2:在测试类中创建两个对象,分别执行两个对象,看输出
@Test public void sprintTest(){ // 读取spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从配置文件中获取对应id所对应的对象 StudentService studentService = (StudentService) context.getBean("studentService"); StudentService studentService1 = (StudentService) context.getBean("studentService"); System.out.println(studentService); System.out.println(studentService1); }3:输出结果分析:只执行了一次bean中的构造方法,因为在创建对象时会执行构造方法,说明单利模式只创建了一次构造方法
执行 StudentService的构造方法 com.doaoao.impl.StudentServiceImpl@64cd705f com.doaoao.impl.StudentServiceImpl@64cd705f
## 在配置文件中将作用域修改为singleton(单例模式)
<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" scope="singleton"/> # 输出结果和上方默认方式相同 执行 StudentService的构造方法 com.doaoao.impl.StudentServiceImpl@418e7838 com.doaoao.impl.StudentServiceImpl@418e7838## 在配置文件中将作用域修改为 prototype(原型模式)每次使用getBean时都会创建
<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" scope="prototype"/> # 输出 <!-- 执行两次构造方法 --> 执行 StudentService的构造方法 执行 StudentService的构造方法 com.doaoao.impl.StudentServiceImpl@5ae50ce6 com.doaoao.impl.StudentServiceImpl@6f96c77
## BeanPostProcessor 接口
实现该接口的类称为bean后处理器,在该类中重写两个方法"postProcessBeforeInitialization" 和 "postProcessAfterInitialization",在获得某个bean的对象后,在该对象的执行之前和执行之后分别调用上面两个方法,我们可以通过这两个方法实现特定的功能
以下下为实例:
package com.doaoao.processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class BeanPostProcessorTest implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行postProcessBeforeInitialization"); // 注意:这里不能返回null,必须返回bean return bean; } @Override public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException { if("studentService".equals(beanName)){ //创建 InvocationHandler invocationHandler = ((Object p,Method method,Object[] args)->{ // 调用study方法时,使用动态代理对其进行增强 if("study".equals(method.getName())) { System.out.println("目标方法开始执行"); // 执行目标方法 Object result = method.invoke(bean, args); System.out.println("目标方法结束执行"); return result; } return method.invoke(bean,args); }); // 增强bean Object proxy = Proxy.newProxyInstance( bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), invocationHandler ); System.out.println("postProcessAfterInitialization执行"); return proxy; } return bean; } }
## bean的生命周期
可以指定bean在初始化和销毁时执行特定的方法
1:在StudentServiceImpl类中创建两个方法 init 和 destroy
package com.doaoao.impl; import com.doaoao.service.StudentService; public class StudentServiceImpl implements StudentService { @Override public void testDao() { System.out.println("Hello World"); } public StudentServiceImpl(){ System.out.println("执行 StudentService的构造方法"); } public void init(){ System.out.println("执行初始化方法"); } public void destroy(){ System.out.println("执行销毁方法"); } }2:在配置文件中添加两个属性 init-method 和 destroy-method 分别指定初始化方法和销毁方法
<bean id="studentService" class="com.doaoao.impl.StudentServiceImpl" init-method="init" destroy-method="destroy"/>3:修改测试类中的内容
@Test public void sprintTest(){ // 读取spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从配置文件中获取对应id所对应的对象 StudentService studentService = (StudentService) context.getBean("studentService"); // 调用对象中的指定方法 studentService.testDao(); // 将context给关闭 ((ClassPathXmlApplicationContext) context).close(); }4:查看输出(当创建时执行的方法,当销毁时执行的方法)
执行 StudentService的构造方法 执行初始化方法 Hello World 执行销毁方法
...
本笔记参考自:小猴子老师教程 http://www.monkey1024.com