代理模式
代理模式的核心就是在不修改原代码的前提下,增强方法行为
静态代理
手写一个代理类,实现目标类相同的接口,内层包着其真实对象。
接口
1 2 3
| public interface UserService { void save(); }
|
目标类
1 2 3 4 5 6
| public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存用户"); } }
|
静态代理类(手写)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class UserServiceProxy implements UserService {
private final UserService target;
public UserServiceProxy(UserService target) { this.target = target; }
@Override public void save() { System.out.println("开启事务"); target.save(); System.out.println("提交事务"); } }
|
使用
1 2 3 4
| UserService service = new UserServiceProxy(new UserServiceImpl())
service.save()
|
优缺点:
- 直观
- 无反射,性能好
- 类爆炸(一个接口一个代理)
- 复用性差
动态代理
代理类是运行时生成的,
方法调用统一拦截,
可复用一套增强逻辑。
JDK动态代理
- 位于
java.lang.reflect.Proxy
- 只能代理接口
- 编写 InvocationHandler 实现类
- 通过 Proxy.newProxyInstance() 创建代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public interface UserService { void save(String name); }
public class UserServiceImpl implements UserService { public void save(String name) { System.out.println("保存用户: " + name); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler { private final Object target;
public MyInvocationHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("【前置增强】方法调用前"); Object result = method.invoke(target, args); System.out.println("【后置增强】方法调用后"); return result; } }
import java.lang.reflect.Proxy;
public class ProxyFactory { public static <T> T getProxy(T target) { InvocationHandler handler = new MyInvocationHandler(target); @SuppressWarnings("unchecked") T proxy = (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler ); return proxy; } }
public class Main { public static void main(String[] args) { UserService realService = new UserServiceImpl(); UserService proxy = ProxyFactory.getProxy(realService); proxy.save("张三"); } }
|
使用匿名函数类
1 2 3 4 5 6 7
| InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } };
|
使用Lambda表达式
1 2 3 4 5 6 7 8
| UserService proxy = (UserService) Proxy.newProxyInstance( loader, interfaces, (proxyObj, method, methodArgs) -> { System.out.println("拦截方法: " + method.getName()); return method.invoke(realService, methodArgs); } );
|
CGLIB动态代理
CGLIB动态代理解决了JDK动态代理只能代理接口的问题,CGLIB使用了ASM技术,能够在运行时修改字节码。CGLIB通过继承的方法实现代理。Spring的AOP中,如果目标对象实现了接口那么使用JDK动态代理,如果没有则使用CGLIB进行代理。
- CGLIB在运行时生成一个目标类的子类
- 重写父类中所有非final,非static,非private的方法
- 在重写方法中插入拦截代码
- 调用原方法使用super.method()委托给父类
- 目标类
1 2 3 4 5 6 7 8 9 10
| public class UserService { public void save(String name) { System.out.println("保存用户: " + name); }
public final void finalizeSave() { System.out.println("最终保存"); } }
|
- 实现MethodInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13
| import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("【前置增强】调用方法: " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("【后置增强】方法结束"); return result; } }
|
- 创建被代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import net.sf.cglib.proxy.Enhancer;
public class Main { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MyMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.save("张三"); proxy.finalizeSave(); } }
|