Bean的装配,也就是bean对象在容器中的创建。然后容器根据我们的代码需求,将Bean对象传递过来。
这里有三种装配方式:
先看项目结构:
package com.fdd.service;
public interface ISomeService {
public void doSome();
public void doOther();
}
public class SomeServiceImpl implements ISomeService {
//添加无参构造器
public SomeServiceImpl() {
System.out.println("无参构造器:SomeServiceImpl实现类");
}
public void doSome() {
System.out.println("doSome实现");
}
public void doOther() {
System.out.println("doOther实现");
}
}
public class MyTest {
@Test
public void test02(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
ISomeService service = (ISomeService) ac.getBean("myService");
service.doSome();
}
}
代码通过getBean方式从容器中获取指定的Bean实例,容器首先会调用Bean类的无参构造器,创建空值的实例对象。
z在上面代码的基础之上直接运行:
有些时候,项目需要使用工厂来创建Bean实例,而不能像前面例子中似的,直接由Spring容器来装配。
public class ServiceFactory {
public ISomeService getISomeService(){
return new SomeServiceImpl();
}
}
注意到这里我们配置的是工厂,而不是bean。这是因为我们的bean是通过工厂来创建的。
@Test
public void test01(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//从Spring容器中获取该工厂
ServiceFactory factory=(ServiceFactory) ac.getBean("myFactory");
//通过factory获取service
ISomeService service=factory.getISomeService();
service.doSome();
}
我们可以看到,我们在工厂中需要去new一个bean。这样做没有降低代码之间的耦合度,所以我们希望通过配置文件,在工厂中声明这个bean
此时我们就不需要获取Factory了,我们直接从容器中获取Service
@Test
public void test01(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//通过factory获取service
ISomeService service=(ISomeService) ac.getBean("someService");
service.doSome();
service.doOther();
}
使用静态工厂创建bean,不需要工厂的实例,
然后修改主配置文件
当通过Spring容器来创建一个bean实例的时候,不仅可以完成bean的实例化,还可以通过scope属性来制定bean的作用域。Spring支持5中作用域:
需要注意的是:
接下来测试一下作用域:
然后修改测试代码:
@Test
public void test01(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//service使用的是singleton
ISomeService service1=(ISomeService) ac.getBean("someService1");
ISomeService service2=(ISomeService) ac.getBean("someService1");
System.out.println("service1=service2 ? "+(service1==service2));
//service使用的是prototype
ISomeService service3=(ISomeService) ac.getBean("someService2");
ISomeService service4=(ISomeService) ac.getBean("someService2");
System.out.println("service3=service4 ? "+(service3==service4));
}
接下来看结果:
bean后处理器是一种特殊的bean,容器中所有的bean在初始化时候,均会自动执行该类的两个方法。由于该bean是由其他bean自动调用执行,不是自己手动调用,因此这个bean不需要id属性
如果我们需要自定义bean,我们就需要实现BeanPostProcessor接口,这个接口中含有两个方法,分别在bean初始化完毕之前和之后执行。最后返回一个增强的bean,也就是添加了自己处理的bean
看一个例子,我们在之前的例子上进行修改、现在我们有两个bean,StudentServiceImpl和TeacherServiceImpl都实现了ISomeService接口。现在我们队StudentServiceImpl进行增强。
package com.fdd.service;
//这个是需要增强的类
public class StudentServiceImpl implements ISomeService {
public void doSome() {
System.out.println(this.getClass().getSimpleName()+",执行了doSome方法");
}
public void doOther() {
System.out.println(this.getClass().getSimpleName()+",执行了doOther方法");
}
}
然后是TeacherServiceImpl
package com.fdd.service;
public class TeacherServiceImpl implements ISomeService {
public void doSome() {
System.out.println(this.getClass().getSimpleName()+",执行了doSome方法");
}
public void doOther() {
System.out.println(this.getClass().getSimpleName()+",执行了doOther方法");
}
}
然后我们创建自己的bean后置器
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//即使不对bean进行增强,也要是方法返回bean,不能为默认的null
//否则将抛出空指针异常
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
//在这里我们增强的是StudentServiceImpl
if("studentService".equals(beanName)){
Object proxy=Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("doSome".equals(method.getName())){
System.out.println("目标方法开始执行的时间"+System.currentTimeMillis());
//执行目标方法
Object result=method.invoke(bean, args);
System.out.println("目标方法结束执行的时间"+System.currentTimeMillis());
return result;
}
return method.invoke(bean, args);
}
});
//将增强之后的代理返回
return proxy;
}
return bean;
}
}
最后在我们的配置文件中声明后处理器
修改测试类:
@Test
public void test01(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//service使用的是singleton
ISomeService studentService=(ISomeService) ac.getBean("studentService");
//这个是增强的方法
studentService.doSome();
studentService.doOther();
System.out.println("===============================");
ISomeService teacherService=(ISomeService) ac.getBean("teacherService");
teacherService.doSome();
teacherService.doOther();
}
看运行结果:
我们可以在配置文件中声明一个bean,在刚刚初始化的时候的行为,也可以声明销毁前的行为
比如我们在上面的TeacherServiceImpl实现类中声明
需要注意的是,我们如果想要看到销毁方法,需要在调用方法之后,关闭ApplicationContext:
@Test
public void test01(){
//创建容器对象,记载Spring配置文件,会从类路径下面查找文件也就是src下面
ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
//service使用的是singleton
ISomeService teacherService=(ISomeService) ac.getBean("teacherService");
teacherService.doSome();
teacherService.doOther();
((ClassPathXmlApplicationContext)ac).close();
}
查看运行结果: