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比照
动静代理 | cglib | jdk |
---|---|---|
是否提供子类代理 | 是 | 否 |
是否提供接口代理 | 是 | 是 |
区别 | 必须依赖于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”/>)