代理
代理顾名思义:代为处理。不是对目标对象的直接操作,而是通过代理对目标对象进行包装,此时可以在目标对象的基础上添加额外的操作以满足业务需求。图示
分类:动态代理、静态代理。
代理三要素:共同接口、真实对象、代理对象
引入代理的原因:
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用【解耦】。
静态代理
public interface Action { public void doSomething(); } public class Proxyc implements Action{ Action realObject; public Proxyc(Action action) { realObject = action; } @Override public void doSomething() { System.out.println("被拦截前..."); realObject.doSomething(); System.out.println("被拦截后..."); } public static void main(String[] args) { Proxyc proxy = new Proxyc(new RealObject()); proxy.doSomething(); } }
优点:扩展原功能,不侵入代码
缺点:假如有10个不同的实际对象,对应10个不同的方法,该如何写呢?
1) 要么创建不同的代理类,代理后这样:
proxy.doSomething()
proxy2.doSomething2()
proxy3.doSomething3()
...
问题:创建多个功能类似的代理类,仅传入的真实对象不同
2) 要么创建一个代理,实现不同的接口:
proxy.doSomething()
proxy.doSomething2()
proxy.doSomething3()
...
问题:代理类不断膨胀
动态代理
代理由静态转为静态源于静态代理引入的额外工作。
动态代理就是我们上面提到的方案一,只不过这些proxy的创建都是自动的并且是在运行期生成的。
很多繁琐的编程可以用动态代理解决
实现方式
- 反射(依赖接口)
- 优点:最小化依赖关系;平滑jdk升级;代码简单
- cglib等(依赖子类)
- 优点:不限制实现接口;只操作关心的类;高性能
反射方式举例
public interface Action { public void doSomething(); } public class RealObject implements Action{ @Override public void doSomething() { System.out.println("I'm RealObject~"); } } public class DynamicProxyHandler implements InvocationHandler { private Object realObject; public DynamicProxyHandler(Object realObject) { this.realObject = realObject; } @Override public Object invoke(Object object, Method method, Object[] args) { Object result = null; try { result = method.invoke(realObject, args); } catch (InvocationTargetException|IllegalAccessException e) { e.printStackTrace(); } return result; } public static void main(String[] args) { RealObject realObject = new RealObject(); Action action = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Action.class}, new DynamicProxyHandler(realObject)); action.doSomething(); } }
通过Proxy.newProxyInstance()生成代理对象,需要传入3个参数:classLoader + 代理接口 + InvocationHandler实例,
其中InvocationHandler接口,该接口定义了一个invoke方法,proxy最是最终生成的一个代理实例,一般不会用到,参数method是被代理目标实例的某个具体的方法,通过它可以发起目标实例方法的反射调用;参数args是通过被代理实例某一个方法的入参,在方法反射调用时候使用,通过代理将横切逻辑代码和业务类的代码编织到了一起。
动态代理的应用场景
日志
监控
鉴权
......
AOP
切面编程,是对OOP(面向对象编程)的一种补充,解决OOP其对对于跨越不同类、对象,纠缠逻辑变现的不足
AOP实例1
public interface Waiter { public void service(); } public class ManWaiter implements Waiter{ @Override public void service() { System.out.println("service..."); } }
public interface BeforeAdvice { public void before(); } public interface AfterAdvice { public void after(); }
@Getter @Setter public class ProxyFactory { Object target; BeforeAdvice beforeAdvice; AfterAdvice afterAdvice; public Object createProxy() { ClassLoader classLoader = this.getClass().getClassLoader(); Class[] interfaces = target.getClass().getInterfaces(); InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (beforeAdvice != null) { beforeAdvice.before(); } Object result = method.invoke(target, args); afterAdvice.after(); return result; } }; Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); return proxyObject; } public static void main(String[] args) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new ManWaiter()); proxyFactory.setBeforeAdvice(new BeforeAdvice() { @Override public void before() { System.out.println("Before Service."); } }); proxyFactory.setAfterAdvice(new AfterAdvice() { @Override public void after() { System.out.println("After Service........."); } }); Waiter waiter = (Waiter)proxyFactory.createProxy(); waiter.service(); } }
AOP实例2
public interface UserService { public void service(); } public class UserServiceImpl implements UserService{ @Override public void service() { System.out.println("In Service......."); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Service end."); } }
public class MethodPerformance { private long start; private long end; String serviceMethod; public MethodPerformance(String serviceMethod) { this.serviceMethod = serviceMethod; start = System.currentTimeMillis(); } public void printPerformance() { end = System.currentTimeMillis(); System.out.println(serviceMethod + " cost Time: " + (end - start)); } } public class PerformanceMonitor { public static ThreadLocal<MethodPerformance> performanceThreadLocal = new ThreadLocal<>(); public static void begin(String method) { System.out.println("Start monitor>>"); MethodPerformance methodPerformance = new MethodPerformance(method); performanceThreadLocal.set(methodPerformance); } public static void end() { System.out.println("End monitor."); performanceThreadLocal.get().printPerformance(); } }
public class PerformanceHandler implements InvocationHandler { Object target; public PerformanceHandler(Object object) { target = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) { Object result = null; try { PerformanceMonitor.begin(target.getClass().getName() + ":" + method.getName()); result = method.invoke(target, args); PerformanceMonitor.end(); } catch (IllegalAccessException| InvocationTargetException e) { e.printStackTrace(); } return result; } public static void main(String[] args) { UserService userService = new UserServiceImpl(); ClassLoader classLoader = userService.getClass().getClassLoader(); Class[] interfaces = userService.getClass().getInterfaces(); InvocationHandler invocationHandler = new PerformanceHandler(userService); UserService obj = (UserService) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); obj.service(); } }