代理模式(静态代理、JDK动态代理、CGLib动态代理、Spring AOP)

定义:为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用;
类型:结构型;

适用场景:
  1. 保护代理对象;
  2. 增强代理对象;
优点:
  1. 将代理对象与真实被调用的目标对象分离;
  2. 一定程度上降低了系统耦合度,扩展性好;
  3. 保护目标对象;
  4. 增强目标对象;
缺点:
  1. 代理模式会造成系统设计中目标类增加;
  2. 在客户端和目标对象之间增加一个代理对象,相对会造成请求处理速度变慢;
    代理模式UML类图
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”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

  1. Aspect(切面):通常是一个类,里面可以定义切入点和通知;
  2. JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用;
  3. Advice(通知):AOP在特定的切入点上执行的增强处理,有before, after, afterReturning, afterThrowing, around;
  4. Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式;
  5. 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---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值