代理实现方式

代理实现方式

代理模式描述:明星一般都会有经纪人,商务联系直接找明星是不可行的,我们就可以通过通过经纪人这个代理去跟明星间接交谈。

优点

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
  • 代理对象可以拓展目标对象的功能
  • 代理对象能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可拓展性

缺点

  • 代理模式会造成系统设计中类的数量增加
  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢
  • 增加了系统的复杂度

根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态:在程序运行时,运用反射机制动态创建而成。

1. 静态代理

首先需要定义一个公共代理接口来约束实现,实现分为委托代理类与代理类,它们均需实现公共代理接口,代理类需通过组合将委托代理类添加实现代理。

/**
 *
 * 静态代理类接口
 *
 * @author Andrew
 * @date 2022/6/16
 */
public interface Cat {
    /**
     * 吃
     * @param foodName 食物名
     * @return 食物名
     */
    String eatFood(String foodName);

    /**
     * 跑
     *
     * @return 是否可以跑
     */
    boolean running();
}


/**
 * 狮子,cat 实现类
 * 作为委托类实现
 *
 * @author Andrew
 * @date 2022/6/16
 */
@Getter
@Setter
@NoArgsConstructor
public class Lion implements Cat {
    private String name;
    private int runningSpeed;

    @Override
    public String eatFood(String foodName) {
        String eat = this.name + "Lion eat food. foodName = " + foodName;
        System.out.println(eat);
        return eat;
    }

    @Override
    public boolean running() {
        System.out.println(this.name + " Lion is running . Speed :" + this.runningSpeed);
        return false;
    }
}


/**
 * 饲养员,实现 Cat
 * 作为静态代理类实现
 *
 * @author Andrew
 * @date 2022/6/16
 */
@Setter
@Getter
@AllArgsConstructor
public class FeederProxy implements Cat{
    private Cat cat;

    @Override
    public String eatFood(String foodName) {
        System.out.println("proxy Lion exec eatFood ");
        return cat.eatFood(foodName);
    }

    @Override
    public boolean running() {
        System.out.println("proxy Lion exec running.");
        return cat.running();
    }
}



/**
 * 静态代理测试类
 * 
 * @author Andrew
 * @date 2022/6/16
 */
public class StaticProxyTest {
    public static void main(String[] args) {
        Lion lion = new Lion();
        lion.setName("狮子 小王");
        lion.setRunningSpeed(100);

        Cat proxy = new FeederProxy(lion);
        proxy.eatFood("水牛");
        // System.out.println(Thread.currentThread().getName()+" -- " + proxy.eatFood("水牛"));
        proxy.running();
    }
}

2. 动态代理

动态代理分为 JDK 动态代理与 CGLIB 动态代理两种方式,它们之间的差别主要在于 JDK 是基于接口实现,为啥不用继承主要是因为代理类会默认继承 Proxy 来实现代理,其主要的实现方法是让代理类实现 InvocationHandler 来重写 invoke 方法实现对委托类的控制。而 CGLIB 的实现方法是通过继承委托类的方式来实现代理,再创建一个方法拦截器来设置回调方法。

2.1 CGLIB-DEMO

/**
 * 委托类
 *
 * @author Andrew
 * @Email Andrew_Zhou@intretech.com
 * @date 2022/6/16
 */
public class Dog {
    public String call() {
        System.out.println("*******dog********");
        return "dog";
    }
}



/**
 * Cglib 方法拦截器
 *
 * @author Andrew
 * @Email Andrew_Zhou@intretech.com
 * @date 2022/6/16
 */
public class CglibMethodInterceptor implements MethodInterceptor {

    public Object cglibProxyGeneratory(Class target) {
        // 创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 为代理类指定需要代理的类,也即是父类
        enhancer.setSuperclass(target);
        // 设置方法拦截器回调引用,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept() 方法进行拦截
        enhancer.setCallback(this);
        // 获取动态代理类对象并返回
        return enhancer.create();
    }


    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before");
        MonitorUtil.start();
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("after");
        MonitorUtil.finish(method.getName());
        return result;
    }
}



/**
 * CGLIB 测试
 *
 * @author Andrew
 * @date 2022/6/16
 */
public class CglibTest {
    public static void main(String[] args) throws Exception {
        // 创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 为代理类指定需要代理的类,也即是父类
        enhancer.setSuperclass(Dog.class);
        // new 一个新的方法拦截器
        CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
        // 设置方法拦截器回调引用,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept() 方法进行拦截
        enhancer.setCallback(cglibMethodInterceptor);
        // 获取动态代理类对象并返回
        Dog dog = (Dog) enhancer.create();
        // 创建cglib 代理类 end
        System.out.println(dog.call());

        // 对于上面这几步,可以新增一个工具方法 放置在 CglibMethodInterceptor 里面;也就有了第二种方法
        // new 一个新的方法拦截器,该拦截器还顺带一个用于创建代理类的工具方法。看起来简单很多
        // cglibMethodInterceptor = new CglibMethodInterceptor();
        // dog = (Dog) cglibMethodInterceptor.cglibProxyGeneratory(Dog.class);
        // System.out.println(dog.call());
    }
}

2.2 JDK-DEMO

/**
 * 动作约束
 *
 * @Author Andrew
 * @Email andrew_zhou1998@163.com
 * @Date 2022/7/2
 */
public interface Action {

    /**
     * 吃
     *
     * @param name 食物名
     */
    void eat(String name);
}





/**
 * 具体实现类
 *
 * @Author Andrew
 * @Email andrew_zhou1998@163.com
 * @Date 2022/7/2
 */
public class Cat implements Action {
    @Override
    public void eat(String name) {
        System.out.println("eat name: " + name);
    }
}



/**
 * 代理实现类
 *
 * @Author Andrew
 * @Email andrew_zhou1998@163.com
 * @Date 2022/7/2
 */
public class Invocation implements InvocationHandler {
    /**
     * 委托类
     */
    private Object target;

    public Invocation(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.err.println("before");

        Object result = method.invoke(target, args);

        System.err.println("end");
        return result;
    }
}


    @Test
    public void jdk() {
        Action action = new com.andrew.study.proxy.dynamic.jdk.Cat();
        Invocation invocation = new Invocation(action);
        Action proxyInstance = (Action) Proxy.newProxyInstance(action.getClass().getClassLoader(), action.getClass().getInterfaces(), invocation);

        proxyInstance.eat("apple");
    }

引用:

https://blog.csdn.net/lx1315998513/article/details/120641124

posted @ 2022-07-01 21:46  生活是很好玩的  阅读(81)  评论(0编辑  收藏  举报