首页 > 技术文章 > 设计模式之代理模式

scorpio-cat 2020-04-16 19:50 原文

代理模式通常分为静态代理和动态代理两种,用于功能增强。

  • 静态代理

静态代理:

1.代理类和目标类都需实现同一接口。

2.代理类中需有目标类实例。

3.代理类实现接口方法,对目标类根据实际情况进行增强,也就是执行一定逻辑,并调用目标类方法。

这样就会导致接口每增加一个方法,则代理类和目标类都需实现该方法。

public interface StaticSourceable {

    public void doMethod();
}

public class StaticSource implements StaticSourceable {

    public void doMethod() {
        System.out.println("业务处理。。。");
    }

}

public class StaticProxy implements StaticSourceable {

    StaticSource source;

    public StaticProxy() {
        // 在代理类的无参构造器中创建目标对象
        this.source = new StaticSource();
    }

    // 代理类对StaticSource的doMethod方法做了增强
    public void doMethod() {
        before();
        try {
            source.doMethod();
        } catch (Exception e) {
            exception();
        }
        after();
    }

    public void before() {
        System.out.println("进入方法。。。");
    }
    
    public void after() {
        System.out.println("执行结束。。。");
    }
    
    public void exception() {
        System.out.println("出现异常。。。");
    }
    
    public static void main(String[] args) {
        StaticSourceable source = new StaticProxy();
        source.doMethod();
    }
}

 

  • 动态代理

动态代理又分为JDK动态代理和CGLib动态代理。

  • JDK动态代理

JDK动态代理:基于接口的代理方式。

1.目标类实现目标类接口。

2.代理类实现 java.lang.reflect.InvocationHandler 接口。

3.代理类中需定义Object目标对象,可通过构造方式或set方式赋值。

4.代理类需实现接口中的 Object invoke(Object proxy, Method method, Object[] args) 方法。

5.代理类提供返回目标类实例的方法,如getProxy(),其是通过直接调用 java.lang.reflect.Proxy 的静态方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 来获取增强后的实例,这是通过反射完成的。

// 目标类接口
public interface IMyJDKTarget {

    void doMethod();
    
}

// 目标类
public class MyJDKTargetImpl implements IMyJDKTarget {

    public void doMethod() {
        System.out.println("业务处理。。。");
    }

}

// 代理类
public class JDKProxyFactory implements InvocationHandler {

    // 目标对象
    private Object target;
    
    public JDKProxyFactory(Object target) {
        super();
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        // 调用目标对象方法
        Object object = method.invoke(target, args);
        after();
        return object;
    }
    
    public Object getProxy() {
        // 直接调用java.lang.reflect.Proxy的静态方法newProxyInstance
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    
    public void before() {
        System.out.println("进入方法。。。");
    }
    
    public void after() {
        System.out.println("执行结束。。。");
    }
    
    public static void main(String[] args) {
        IMyJDKTarget target = (IMyJDKTarget) new JDKProxyFactory(new MyJDKTargetImpl()).getProxy();
        target.doMethod();
    }
    
}

 

  • CGLib动态代理

CGLib动态代理:基于类的代理方式。

1.目标类不需要实现接口。

2.代理类实现 net.sf.cglib.proxy.MethodInterceptor接口。

3.代理类中需定义Object目标对象,可通过构造方式或set方式赋值。

4.代理类需实现接口中的 Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)方法。

5.代理类中提供返回增强后的目标对象方法,如getProxy(),其是通过创建增强器Enhancer,设置需要增强的目标对象和回调方法后,调用create()方法来获取到增强后的实例对象。

// 目标类(不需要接口)
public class MyCgLibTarget {

    public void doMethod() {
        System.out.println("业务处理。。。");
    }
}

// 代理类
public class CgLibProxyFactory implements MethodInterceptor {
    // 目标对象
    private Object target;
    
    public CgLibProxyFactory(Object target) {
        super();
        this.target = target;
    }
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        // 调用目标对象方法
        Object object = proxy.invoke(target, args);
        after();
        return object;
    }
    
    public Object getProxy() {
        // 创建增强器
        Enhancer enhancer = new Enhancer();
        // 设置需要增强的类的类对象
        enhancer.setSuperclass(target.getClass());
        // 设置回调函数
        enhancer.setCallback(this);
        // 获取增强之后的代理对象
        return enhancer.create();
    }
    
    public void before() {
        System.out.println("进入方法。。。");
    }
    
    public void after() {
        System.out.println("执行结束。。。");
    }
    
    public static void main(String[] args) {
        MyCgLibTarget target = (MyCgLibTarget) new CgLibProxyFactory(new MyCgLibTarget()).getProxy();
        target.doMethod();
    }

}

 

推荐阅读