【Spring】IOC、AOP和动态代理(底层原理)
1、Spring框架理解Spring框架主要有两个核心:IoC(控制反转)和AOP(面向切面编程)对于Spring,核心就是IOC容器,这个容器说白了就是把你放在里面的对象(Bean)进行统一管理,你不用考虑对象如何创建如何销毁,从这方面来说,所谓的控制反转就是获取对象的方式被反转了。既然你都把对象交给人家Spring管理了,那你需要的时候不得给人家要呀。这就是依赖注入(DI)!再想下,注入方式有
1、Spring框架理解
Spring框架主要有两个核心:IoC(控制反转)和AOP(面向切面编程)
对于Spring,核心就是IOC容器,这个容器说白了就是把你放在里面的对象(Bean)进行统一管理,你不用考虑对象如何创建如何销毁,从这方面来说,所谓的控制反转就是获取对象的方式被反转了。既然你都把对象交给人家Spring管理了,那你需要的时候不得给人家要呀。这就是依赖注入(DI)!再想下,注入方式有两种,构造方法注入和setter方法注入
对于AOP,举例说明:比如你写了个方法用来做一些事情,但这个事情要求登录用户才能做,你就可以在这个方法执行前验证一下,执行后记录下操作日志,把前后的这些***与业务逻辑无关的代码抽取出来放一个类里***,但是在运行的时候,两个毫无相关的类在运行内存中又会结合在一起,这个类就是切面(Aspect),这个被环绕的方法就是切点(Pointcut),你所做的执行前执行后的这些方法统一叫做增强处理(Advice)。
2、动态代理(AOP原理)
1.AoP是如何实现的呢?
通过动态代理的方式实现
2.那动态代理是如何实现的?
自己手动写的代理类就是静态代理,手写代理类有两种思路,一是通过继承代理类的方式实现其子类,重写父类方法;二是与被代理类实现共同的一个接口,尴尬的是被代理类未必会有接口。
所以,简单来说,动态代理就是不用自己手动去写代理类,而是交给程序自动生成代理类(在程序运行期间由JVM根据反射等机制动态生成源码)
所以,动态代理也有两种方式:
一、基于接口的JDK动态代理
二、基于父类继承的cglib动态代理
3、JDK的动态代理
使用JDK的动态代理去生成代理只需要一行代码:
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass.getClassLoader(), target.getClass.getInterfaces(), new LogHandler(new target()));
传入的参数中其实就俩,一是被代理类的类对象,二是自定义的增强处理代码。下面看下LogHandler源码:
public class LogHandler implements InvocationHandler{
private Object target;
public LogHandler(Object object){
super();
this.target = object;
}
//增强处理
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object I = method.invoke(target,args);
return I;
}
}
观察InvocationHandler实现类的源码可以发现,首先是定义了一个含参构造方法,该参数即为要代理的实例对象,观察target对象的使用位置在method.invoke()方法的参数中,不难看出,目的也就是为了执行目标方法。那重写的invoke()方法的三个参数又是什么呢?顾名思义,
proxy:动态生成的代理对象
method:目标方法的实例
args:目标方法的参数
从Proxy.newProxyInstance()的方法参数中包含了被代理类的接口的类对象也不难得知,JDK的动态代理只能代理实现了接口的类, 没有实现接口的类不能实现动态代理。
关于Jdk动态代理的原理,我归纳得出四步
- 声明一段源码,源码动态产生动态代理
- 源码产生java文件,对java文件进行编译
- 得到编译生成后的class文件
- 把class文件load到内存之中,产生代理类对象返回即可。
依照这四步流程,实现一个Demo版的Jdk动态代理框架,问题不大。
4、cglib的动态代理
cglib使用动态代理的流程:
public static void main(String[] args) {
//创建增强器
Enhancer enhancer = new Enhancer();
//设置被代理类(父类/目标)
enhancer.setSuperclass(Target.class);
//设置回调函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //增强处理... //增强处理...
Object invoke= proxy.invokeSuper(target, args);//代理类调用父类的方法
//增强处理...
return invoke;
}
});
//创建代理类并使用回调
Target proxy = (Target) enhancer.create();
//执行目标方法
Target.save();
}
从上面的代码看到,cglib的使用流程还是很清晰明了,各种参数顾名思义,和jdk的区别不大。生成的代理对象直接被该类引用,与我们认知的基于继承的动态代理没冲突。不过这种基于继承的方式就没有什么缺点吗?最明显的一点就是final修饰的类无法使用。
5、Spring用哪种?
Spring会根据具体的Bean是否具有接口去选择动态代理方式,如果有接口,使用的是Jdk的动态代理方式,如果没有接口,使用的是cglib的动态代理方式。
更多推荐
所有评论(0)