核心思想:应用代理对象来代替原始对象实现对象拜访,这样就能够在不批改原始对象代码的前提下,拓展原始对象的额定性能。
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; }}
创立代理类
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; }}
测试
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()
毛病:
- 接口每新增一个接口,对应的指标类和代理类都须要批改。
- 须要对每个指标类都独自写一个代理类。
2. 动静代理
在运行时利用反射机制动静生成类字节码,并加载到JVM中的。
2.1 JDK动静代理
外围: InvocationHandler接口和Proxy类
JDK动静代理实现步骤:
- 定义一个接口及其实现类。
- 自定义
InvocationHandler
并重写invoke
办法,在invoke
办法中会调用原生办法并进行拓展逻辑解决。 - 通过
Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler h)
办法创立代理对象。
例子:
定义一个接口及其实现类。
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; }}
定义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; }}
获取代理对象的工厂,应用Proxy.newProxyInstance()办法创立代理对象
public class JdkProxyFactory { public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), // 指标类的类加载 target.getClass().getInterfaces(), // 代理须要实现的接口,可指定多个 new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler ); }}
应用Proxy.newProxyInstance()办法创立代理对象
SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());smsService.send("java");// 输入// before method send// send message:java// after method send
毛病:
- 只能代理实现了接口的类。
2.2 cglib动静代理
**外围:通过继承的形式实现代理,MethodIntercept接口和Enhancer类。
cglib动静代理实现步骤:
- 定义一个类。
- 自定义
MethodIntercept
并重写intercept
办法,intercept
用于拦挡原生类的办法,相似于JDK动静代理中的invoke
。 - 通过
Enhancer
的create()
创立代理对象。
例子:
定义一个类
public class AliSmsService { public String send(String message) { System.out.println("send message:" + message); return message; }}
自定义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; }}
通过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(); }}
理论应用
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...