1.代理模式

代理是设计模式的一种,代理类为委托类提供音讯预处理,音讯转发,预先音讯解决等性能。Java中的代理分为三种角色: 代理类、委托类、接口

为了放弃行为的一致性,代理类和委托类通常会实现雷同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这两头一层,能无效管制对委托类对象的间接拜访,也能够很好地暗藏和爱护委托类对象,同时也为施行不同控制策略预留了空间,从而在设计上取得了更大的灵活性。Java 动静代理机制以奇妙的形式近乎完满地实际了代理模式的设计理念。

Java中的代理依照代理类生成机会不同又分为动态代理动静代理

  • 动态代理:动态代理的特点是, 为每一个业务加强都提供一个代理类, 由代理类来创立代理对象. 上面咱们通过动态代理来实现对转账业务进行身份验证.
  • 动静代理:动态代理会为每一个业务加强都提供一个代理类, 由代理类来创立代理对象, 而动静代理并不存在代理类, 代理对象间接由代理生成工具动静生成.

1.2.动态代理

Java中的动态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject)。如下示例:

接口 Subject.java
public interface Subject {        public void sayHello();    }
委托类 RealSubject.java
public class RealSubject implements Subject {    @Override    public void sayHello() {        System.out.println("hello!");    }    }
代理类 ProxySubject.java
class ProxySubject implements Subject {    private Subject subject;    public ProxySubject(Subject subject) {        this.subject = subject;    }        @Override    public void sayHello() {        System.out.println("Before say hello...");        subject.sayHello();        System.out.println("After say hello...");    }    }
测试方法 main
    public static void main(String[] args) {        Subject subject = new RealSubject();        ProxySubject proxySubject = new ProxySubject(subject);        proxySubject.sayHello();    }

依照示例中,代理模式实现的性能,能够了解成一个简易版的Spring AOP 实现,那咱们就拿代理模式和Spring AOP做比照。

代理模式的组成包含:接口、委托类和代理类。咱们在Spring中应用AOP,通常针对的“切面”,也就是委托类会有很多。接口和委托类是业务代码,必不可少,但代理类这是为了代理模式而创立的。如果每个委托类对应代理类的逻辑都不一样还好,可 如果多个委托类复用同一个代理类办法,就显得很冗余了

1.2. jdk动静代理

为了解决这类问题,jdk有提供动静代理的实现,即提供可复用的代理类。动静代理就是要生成一个包装类对象,因为代理的对象是动静的,所以叫动静代理。

JDK动静代理是应用 java.lang.reflect 包下的代理类来实现. JDK动静代理动静代理必须要有接口.

因为咱们须要加强,这个加强是须要留给开发人员开发代码的,因而代理类不能间接蕴含被代理对象,而是一个InvocationHandler,该InvocationHandler蕴含被代理对象,并负责散发申请给被代理对象,散发前后均能够做加强。从原理能够看出,JDK动静代理是“对象”的代理。

下面的代码实现,能够批改成上面这种形式,同样能实现性能。

接口 Subject.java
public interface Subject {        public void sayHello();    }
委托类 RealSubject.java
public class RealSubject implements Subject {    @Override    public void sayHello() {        System.out.println("hello!");    }    }
代理类 InvocationHandlerImpl.java
public class InvocationHandlerImpl implements InvocationHandler {    private Object object;    public InvocationHandlerImpl(Object object) {        this.object = object;    }    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("Before say hello...");        Object returnValue = method.invoke(subject, args);        System.out.println("After say hello...");        return returnValue;    }}
测试方法 main
    public static void main(String[] args) {        Subject realSubject = new RealSubject();        InvocationHandler handler = new InvocationHandlerImpl(realSubject);        ClassLoader loader = realSubject.getClass().getClassLoader();        Class[] interfaces = realSubject.getClass().getInterfaces();        Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);        subject.sayHello();    }

1.3. cglib动静代理

JDK动静代理必须要有接口, 但如果要代理一个没有接口的类该怎么办呢? 这时咱们能够应用CGLIB动静代理. CGLIB动静代理的原理是生成指标类的子类, 这个子类对象就是代理对象, 代理对象是被加强过的.

留神: 不论有没有接口都能够应用CGLIB动静代理, 而不是只有在无接口的状况下能力应用.

委托类 RealSubject.java
public class RealSubject {    public void sayHello() {        System.out.println("hello!");    }}
代理类 MethodInterceptorImpl.java
public class MethodInterceptorImpl implements MethodInterceptor {    @Override    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {        System.out.println("Before say hello...");        Object returnValue= methodProxy.invokeSuper(obj, args);        System.out.println("After say hello...");        return returnValue;    }}
测试方法 main
    public static void main(String[] args) {        RealSubject target = new RealSubject();        RealSubject proxy = (RealSubject) Enhancer.create(target.getClass(),                new MethodInterceptorImpl());        proxy.sayHello();    }

2. Spring AOP实现原理

对于Spring AOP的概念我就不多说了,大家都晓得是基于动静代理实现的,就是下面咱们说的这些,那么具体是怎么实现的呢?

在代理模式中有三种外围的角色:委托类、代理类、接口,而gclib动静代理中“接口”是非必须的,因而咱们关注Spring AOP中 委托类代理类的实现。

委托类

回顾一下Aop的实现代码:须要在实现类上加上@Aspect的注解,还须要通过@Pointcut注解来申明“切点”,即委托类和委托办法的门路。

有了这些信息就足够获取委托类了。这里充沛用到Java反射,先找到蕴含@Aspect注解的类,而后找到该类下的@Pointcut注解,读取所定义的委托类和委托办法门路,就齐全能拿到委托类对象。

代理类

因为咱们应用的是动静代理,这里的代理类能够被替换成代理办法。同样,咱们在@Aspect注解的类中,用@Around、@Before、@After润饰的办法,就是咱们想要的代理办法。

总结
咱们能够通过BeanFactoryPostProcessor的实现类,实现对所有BeanDefinition的扫描,找出咱们定义的所有的切面类,而后循环外面的办法,找到切点、以及所有的告诉办法,而后依据注解判断告诉类型(也就是前置,后置还是盘绕),最初解析切点的内容,扫描出所有的指标类。这样就获取了委托类代理办法

当初委托类代理办法 都有了,咱们晓得在动静代理模式中,最终的目标是将委托类的办法执行,替换成代理类的办法执行。然而在Spring中,咱们是感知不到代理类的,咱们在代码中还是调用原委托类的办法,那么Spring框架是如何神不知鬼不觉地将委托类替换成代理类的呢?

这就波及到咱们之前无关Ioc文章的内容了,在Bean的生命周期中,Bean在初始化前后会执行BeanPostProcessor的办法。能够把它了解成一个加强办法,能够将原始的Bean通过“加强”解决后加载到Ioc容器中。这就是一个人造的代理办法,原始的Bean就是委托类,在此处实现代理办法生成代理类,再将代理类加载进Ioc容器。

3. jdk动静代理和cglib比照

动静代理cglibjdk
是否提供子类代理
是否提供接口代理
区别必须依赖于CGLib的类库,然而它须要类来实现任何接口代理的是指定的类生成一个子类,笼罩其中的办法实现InvocationHandler,应用Proxy.newProxyInstance产生代理对象,被代理的对象必须要实现接口
Cglib和jdk动静代理的区别?

1、Jdk动静代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来解决
2、 Cglib动静代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过批改其字节码生成子类来解决

什么时候用cglib什么时候用jdk动静代理?

1、指标对象生成了接口 默认用JDK动静代理
2、如果指标对象应用了接口,能够强制应用cglib
3、如果指标对象没有实现接口,必须采纳cglib库,Spring会主动在JDK动静代理和cglib之间转换

JDK动静代理和cglib字节码生成的区别?

1、JDK动静代理只能对实现了接口的类生成代理,而不能针对类
2、Cglib是针对类实现代理,次要是对指定的类生成一个子类,笼罩其中的办法,并笼罩其中办法的加强,然而因为采纳的是继承,所以该类或办法最好不要生成final,对于final类或办法,是无奈继承的

Cglib比JDK快?

1、cglib底层是ASM字节码生成框架,然而字节码技术生成代理类,在JDL1.6之前比应用java反射的效率要高
2、在jdk6之后逐渐对JDK动静代理进行了优化,在调用次数比拟少时效率高于cglib代理效率
3、只有在大量调用的时候cglib的效率高,然而在1.8的时候JDK的效率已高于cglib
4、Cglib不能对申明final的办法进行代理,因为cglib是动静生成代理对象,final关键字润饰的类不可变只能被援用不能被批改

Spring如何抉择是用JDK还是cglib?

1、当bean实现接口时,会用JDK代理模式
2、当bean没有实现接口,用cglib实现
3、能够强制应用cglib(在spring配置中退出<aop:aspectj-autoproxy proxyt-target-class=”true”/>)