spring核心内容一说起来就是IOC和AOP两大功能,大概是这样:
IOC
控制反转,就是将本来自己要创建和维护的对象,交给容器去管理,将程序员从不同对象之间的复杂的依赖关系中解放出来了
操作上来说,就是将bean注册进容器,需要时从容器中获取,而不用自己去new
AOP
面向切面编程,一般用来解决一些交叉的业务,比如打印日志,事务等。AOP将要交叉的业务模块化,把本来要写在程序内的一些重复代码提取出来,并将这些模块在程序前后调用(注意不是实现将业务代码拼接,是调用,AOP底层实现是动态代理,就是代理对象通过调用目标对象的同名方法,并在调用前后加增强代码,所以有时候你所使用的bean可能是代理类而不是真正你自己注册入容器的bean)
深入来讲,涉及到两个东西,一个BeanDefinition还有一个后置处理器
说到BeanDefinition之前,先看一下spring容器的运行原理
图中的1、2、3步是spring的启动阶段,我们可以看到,spring启动过程
- Spring首先会扫描解析指定位置的所有的类得到Resources(可以理解为.Class文件)
- 然后依照TypeFilter和@Conditional注解决定是否将这个类解析为BeanDefinition存放在bean定义注册表中
- 最后在把一个个BeanDefinition取出实例化成bean放入bean的缓存池
BeanDfinition在这里就和Class类差不多,用于描述一个bean实例
所以spring运行原理中的第一步,即spring解析了所有的配置,并将解析出的类已BeanDefinition存入在BeanDefinitonMap中
接下来就是创建Bean,在创建bean的时候并不是我们通常所想的那样,直接创建对应的实例,而是spring根据我们的配置(比如需要开启事务)会通过代理返回一个代理类,这就是后置处理器做了工作。
上图是spring容器提供的一些后置处理器接口,比如BeanPostProcessor就是支持在bean在初始化前后对bean进行处理
以下我们使用BeanPostProcessor返回当前Bean的代理对象
@Configuration//表明该类是一个配置类,相当于AppConfig.xml
@ComponentScan//用于配置扫描的包,默认是扫描该配置类所在的包及其子包
public class AppConfig {
}
public interface Calculator {
int add(int a, int b);
}
@Component
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
return a+b;
}
}
@Component
public class MyAspectJAutoProxyCreator implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
final Object obj = o;
//如果当前经过BeanPostProcessors的Bean是Calculator类型,我们就返回它的代理对象,否则就返回他本身
if(o instanceof Calculator){
Object proxyObj = Proxy.newProxyInstance(
this.getClass().getClassLoader(),
o.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始计算...");
Object object = method.invoke(obj,args);
System.out.println((int)object);
System.out.println("计算结束...");
return object;
}
});
return proxyObj;
}
return obj;
}
}
public class TestPostProcess {
public static void main(String[] args) {
System.out.println("容器启动成功!");
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
System.out.println("===============================================");
Calculator calculator = (Calculator) applicationContext.getBean(Calculator.class);
calculator.add(1, 1);
}
}
把MyAspectJAutoProxyCreator类的注解@Component注释后,返回结果如下