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动态代理的原理,我归纳得出四步

  1. 声明一段源码,源码动态产生动态代理
  2. 源码产生java文件,对java文件进行编译
  3. 得到编译生成后的class文件
  4. 把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的动态代理方式。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐