核心思想:应用代理对象来代替原始对象实现对象拜访,这样就能够在不批改原始对象代码的前提下,拓展原始对象的额定性能。

1. 动态代理

动态代理实现步骤:

  1. 定义一个接口和实现类。
  2. 定义一个代理类也实现该接口。
  3. 将指标对象注入到代理类中,而后在代理类的办法中调用对应指标类中的办法。

例子:

  1. 定义发短信的接口及其实现类

    public interface SmsService { String send(String message);}public class SmsServiceImpl implements SmsService { @Override public String send(String message) {     System.out.println("send message:" + message);     return message; }}
  2. 创立代理类

    public class SmsProxy implements SmsService { private final SmsServiceImpl smsServiceImpl; public SmsProxy(SmsService smsService) {     this.smsService = smsService; } @Override public String send(String message) {     //调用办法之前,咱们能够增加本人的操作     System.out.println("before method send()");     smsService.send(message);     //调用办法之后,咱们同样能够增加本人的操作     System.out.println("after method send()");     return null; }}
  3. 测试

    public class Main { public static void main(String[] args) {     SmsService smsService = new SmsServiceImpl();     SmsProxy smsProxy = new SmsProxy(smsService);     smsProxy.send("java"); }}// 输入// before method send()// send message:java// after method send()

    毛病

  4. 接口每新增一个接口,对应的指标类和代理类都须要批改。
  5. 须要对每个指标类都独自写一个代理类。

2. 动静代理

在运行时利用反射机制动静生成类字节码,并加载到JVM中的。

2.1 JDK动静代理

外围: InvocationHandler接口和Proxy类
JDK动静代理实现步骤:

  1. 定义一个接口及其实现类。
  2. 自定义InvocationHandler并重写invoke办法,在invoke办法中会调用原生办法并进行拓展逻辑解决。
  3. 通过Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h) 办法创立代理对象。

例子:

  1. 定义一个接口及其实现类。

    public interface SmsService { String send(String message);}public class SmsServiceImpl implements SmsService { @Override public String send(String message) {     System.out.println("send message:" + message);     return message; }}
  2. 定义JDK动静代理类

    public class DebugInvocationHandler implements InvocationHandler { /**  * 代理类中的实在对象  */ private final Object target; public DebugInvocationHandler(Object target) {     this.target = target; } // invoke() 办法: 当咱们的动静代理对象调用原生办法的时候,最终实际上调用到的是 invoke() 办法,而后 invoke() 办法代替咱们去调用了被代理对象的原生办法。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {     //调用办法之前,咱们能够增加本人的操作     System.out.println("before method " + method.getName());     Object result = method.invoke(target, args);     //调用办法之后,咱们同样能够增加本人的操作     System.out.println("after method " + method.getName());     return result; }}
  3. 获取代理对象的工厂,应用Proxy.newProxyInstance()办法创立代理对象

    public class JdkProxyFactory { public static Object getProxy(Object target) {     return Proxy.newProxyInstance(             target.getClass().getClassLoader(), // 指标类的类加载             target.getClass().getInterfaces(),  // 代理须要实现的接口,可指定多个             new DebugInvocationHandler(target)   // 代理对象对应的自定义 InvocationHandler     ); }}
  4. 应用Proxy.newProxyInstance()办法创立代理对象

    SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());smsService.send("java");// 输入// before method send// send message:java// after method send

毛病:

  1. 只能代理实现了接口的类。

2.2 cglib动静代理

**外围:通过继承的形式实现代理,MethodIntercept接口和Enhancer类。
cglib动静代理实现步骤:

  1. 定义一个类。
  2. 自定义MethodIntercept并重写intercept办法,intercept用于拦挡原生类的办法,相似于JDK动静代理中的invoke
  3. 通过Enhancercreate()创立代理对象。

例子:

  1. 定义一个类

    public class AliSmsService { public String send(String message) {     System.out.println("send message:" + message);     return message; }}
  2. 自定义MethodIntercept并重写intercept办法

    public class DebugMethodInterceptor implements MethodInterceptor { /**  * @param o           被代理的对象(须要加强的对象)  * @param method      被拦挡的办法(须要加强的办法)  * @param args        办法入参  * @param methodProxy 用于调用原始办法  */ @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {     //调用办法之前,咱们能够增加本人的操作     System.out.println("before method " + method.getName());     Object object = methodProxy.invokeSuper(o, args);     //调用办法之后,咱们同样能够增加本人的操作     System.out.println("after method " + method.getName());     return object; }}
  3. 通过Enhancer获取代理类

    public class CglibProxyFactory { public static Object getProxy(Class<?> clazz) {     // 创立动静代理加强类     Enhancer enhancer = new Enhancer();     // 设置类加载器     enhancer.setClassLoader(clazz.getClassLoader());     // 设置被代理类     enhancer.setSuperclass(clazz);     // 设置办法拦截器     enhancer.setCallback(new DebugMethodInterceptor());     // 创立代理类     return enhancer.create(); }}
  4. 理论应用

    AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);aliSmsService.send("java");// 输入// before method send// send message:java// after method send

2.3 JDK动静代理和cglib动静代理区别

  • JDK动静代理只能代理实现了接口的类,而cglib能够代理未实现任何接口的类。cglib通过生成原生类的子类来拦挡被代理类的的办法调用,因而cglib不能代理被final润饰的类和办法。
  • jdk效率更高。SpringAOP中如果原生类实现了接口,默认应用JDK动静代理,否则应用cglib。
参考文献:
https://snailclimb.gitee.io/j...