定义:为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用;
类型:结构型;
适用场景:
- 保护代理对象;
- 增强代理对象;
优点:
- 将代理对象与真实被调用的目标对象分离;
- 一定程度上降低了系统耦合度,扩展性好;
- 保护目标对象;
- 增强目标对象;
缺点:
- 代理模式会造成系统设计中目标类增加;
- 在客户端和目标对象之间增加一个代理对象,相对会造成请求处理速度变慢;
jdk静态代理:
jdk静态代理实现比较简单,一般是代理对象直接包装了被代理对象。只能为一个被代理类服务,如果需要代理的类比较多,那么会产生过多的代理类。jdk静态代理在编译时产生class文件,运行时无需产生,可直接使用。
public class Tank implements Movable{
public void move() throws InterruptedException {
System.out.println("tank move---");
Thread.sleep(new Random().nextInt(10000));
}
public static void main(String[] args) throws InterruptedException {
new TankProxy(new Tank()).move();
}
}
class TankProxy implements Movable{
private Movable movable;
public TankProxy(Movable movable) {
this.movable = movable;
}
public void move() throws InterruptedException {
System.out.println("tank start---");
movable.move();
System.out.println("tank end---");
}
}
interface Movable{
void move() throws InterruptedException;
}
// 输出:
tank start---
tank move---
tank end---
jdk动态代理
jdk动态代理会根据被代理对象生成一个继承了Proxy类,并实现了该业务接口的jdk代理类,该类的字节码会被传进去的ClassLoader加载,创建了jdk代理对象实例。jdk动态代理必须实现接口,通过反射来动态代理方法,消耗系统性能。但是无需产生过多的代理类,避免了重复代码的产生,系统更加灵活。
class TankHandler implements InvocationHandler{
Tank tank;
public TankHandler(Tank tank) {
this.tank = tank;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("tank start---");
Object invoke = method.invoke(tank, args);
System.out.println("tank end---");
return invoke;
}
}
public static void main(String[] args) throws InterruptedException {
Tank tank = new Tank();
Movable movable = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader()
, new Class[]{Movable.class}, new TankHandler(tank));
movable.move();
}
// 输出:
tank start---
tank move---
tank end---
CGLib动态代理
CGLib动态代理是继承代理,通过ASM字节码框架修改字节码生成新的子类,重写并增强方法的功能。CGLib动态代理无需实现接口,通过生成子类字节码来实现,jdk8以后比反射快一点。但是由于cglib会继承被代理类,需要重写被代理方法,所以被代理类不能是final类,被代理方法不能是final。
class ProxyMethodInterceptor implements MethodInterceptor{
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("tank start---");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("tank end---");
return invoke;
}
}
public static void main(String[] args) throws InterruptedException {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
enhancer.setCallback(new ProxyMethodInterceptor());
Tank tank = (Tank) enhancer.create();
tank.move();
}
// 输出:
tank start---
tank move---
tank end---
Spring AOP:
AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
- Aspect(切面):通常是一个类,里面可以定义切入点和通知;
- JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用;
- Advice(通知):AOP在特定的切入点上执行的增强处理,有before, after, afterReturning, afterThrowing, around;
- Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式;
- AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类;
@Aspect
public class AopProxy {
@Before("execution (void designmodel.structral.proxy.aop.Tank.move())")
public void before(){
System.out.println("tank start---");
}
@After("execution (void designmodel.structral.proxy.aop.Tank.move())")
public void after(){
System.out.println("tank end---");
}
}
// 输出:
tank start---
tank move---
tank end---