结构型之代理模式

编程不只是一门技术,更是一门艺术!

结构型

代理模式

客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象,同时也可以通过代理对象来控制对实际对象的访问。代理模式也可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。

  • 静态代理:实质是自己手写代理类,也就是在程序运行前就已经存在的编译好的代理类。
  • 动态代理:在运行时根据需要动态生成类字节码,并加载到JVM中。

在这里插入图片描述

静态代理

创建一个接口,然后创建被代理类并实现该接口。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。

缺点:

  • 代理类需要实现接口的全部抽象方法,一旦目标接口增加方法目标类和代理类均需要修改。
  • 每一个目标类均需要一个代理类,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。
public interface UserDao {
    
      
    void save();   
}

public class UserDaoImpl implements UserDao {
    
    
    @Override
    public void save() {
    
    
        System.out.println("正在保存用户...");
    }
}

public class TransactionHandler implements UserDao {
    
    
    //  目标代理对象
    private UserDao target;
    
    public TransactionHandler(UserDao target) {
    
    
        this.target = target;  // 构造代理对象时传入目标对象
    }
    @Override
    public void save() {
    
    
        //调用目标方法前的处理
        System.out.println("开启事务控制...");
        //调用目标对象的方法
        target.save();
        //调用目标方法后的处理
        System.out.println("关闭事务控制...");
    }
}

JDK动态代理

JDK动态代理中,代理类在运行时利用反射机制动态创建,不针对某一个接口,不针对某一个特定的被代理类,达到了代理类的复用。

public interface IHello {
    
    
    void sayHello();
}

public class HelloImpl implements IHello {
    
    
    @Override
    public void sayHello() {
    
    
        System.out.println("Hello world!");
    }
}

public class MyInvocationHandler implements InvocationHandler {
    
    

    /** 目标对象 */
    private 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 rs = method.invoke(target,args);
        System.out.println("------插入后置处理代码-------------");
        return rs;
    }
}

public class Test {
    
    
    public static void main(String[] args) throws Exception, InvocationTargetException {
    
    
        //  动态创建代理类
        IHello  iHello = (IHello) Proxy.newProxyInstance(
            IHello.class.getClassLoader(), // 加载接口的类加载器
            new Class[]{
    
    IHello.class}, // 目标类的所有接口,目的是代理接口中的方法
            new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
        iHello.sayHello();  // 通过代理类调用目标方法
    }
}

CGLIB动态代理

JDK代理要求被代理的类必须实现接口,有很强的局限性,但是CGLIB动态代理则没有此类强制性要求。CGLIB会让生成的代理类继承被代理类(所以final方法不会被代理,final类不会被代理),代理类中会为委托方法生成两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法,另一个是代理类独有的方法。在CGLIB中,方法的调用并不是通过反射来完成的,而是通过FastClass机制直接对方法进行调用,FastClass机制就是对一个类的方法建立索引,通过索引来直接调用相应的方法,提高效率。

 public class HelloService {
    
    
    public HelloService() {
    
    
        System.out.println("HelloService构造");
    }
 
    /**
     * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
     */
    final public String sayOthers(String name) {
    
    
        System.out.println("HelloService:sayOthers>>"+name);
        return null;
    }
 
    public void sayHello() {
    
    
        System.out.println("HelloService:sayHello");
    }
}

public class MyMethodInterceptor implements MethodInterceptor{
    
    
 
    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
}

public class Client {
    
    
    public static void main(String[] args) {
    
     
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(HelloService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        // 通过代理对象调用目标方法
        proxy.sayHello();
    }
}

Guess you like

Origin blog.csdn.net/zhang_qing_yun/article/details/119672574