代理模式

强颜欢笑 提交于 2020-08-11 15:00:19

一 代理模式简介

代理(Proxy)是一种设计模式 提供了对目标对象另外的访问方式

代理对象代理目标对象 达到增强目标对象功能的目的

 

二 静态代理

需要定义接口或者父类 代理对象与目标对象一起实现相同接口或者继承相同父类

优点: 在不修改目标对象的功能前提下 对目标功能扩展

缺点: 因为代理对象需要与目标对象一起实现相同接口或者继承相同父类 所以会有很多代理类 导致类太多 同时 如果接口增加方法 代理对象与目标对象都要维护

1. 接口

/**
 * 接口
 * Created by Hy on 2020/7/10.
 */
public interface IUserService {

    void insertUser();

    String deleteUser(int id);
}

2. 目标对象

/**
 * 目标对象
 * Created by Hy on 2020/7/10.
 */
public class UserService implements IUserService {

    @Override
    public void insertUser() {
        System.out.println("insert ok");
    }

    @Override
    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

3. 代理对象

/**
 * 代理对象
 * Created by Hy on 2020/7/13.
 */
public class UserServiceProxy implements IUserService {

    private IUserService target; //目标对象

    public UserServiceProxy(IUserService target) {
        this.target = target;
    }

    @Override
    public void insertUser() {
        System.out.println("增强方法体 1/2");
        target.insertUser();
        System.out.println("增强方法体 2/2");
    }

    @Override
    public String deleteUser(int id) {
        id++; //增强参数
        String s = target.deleteUser(id);
        s = s + "!!!"; //增强返回值
        return s;
    }
}

4. 测试

@Test
public void test01() {
    // 创建目标对象
    UserService target = new UserService();
    // 创建代理对象
    UserServiceProxy proxy = new UserServiceProxy(target);
    // 使用代理对象调用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 

三 动态代理(接口代理)

需要定义接口让目标对象实现 使用java.lang.reflect.Proxy动态的在内存中构建代理对象

优点: 在不修改目标对象的功能前提下 对目标功能扩展 代理对象不需要实现接口

缺点: 目标对象一定要实现接口 否则不能用动态代理

1. 接口

/**
 * 接口
 * Created by Hy on 2020/7/10.
 */
public interface IUserService {

    void insertUser();

    String deleteUser(int id);
}

2. 目标对象

/**
 * 目标对象
 * Created by Hy on 2020/7/10.
 */
public class UserService implements IUserService {

    @Override
    public void insertUser() {
        System.out.println("insert ok");
    }

    @Override
    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

3. 代理工厂

/**
 * 代理工厂
 * Created by Hy on 2020/7/13.
 */
public class ProxyFactory {

    private Object target; //目标对象

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

    public Object createProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 代理对象调用的所有方法都会触发该方法执行
             * @param proxy 代理对象
             * @param method 被代理的方法
             * @param args 被代理的方法传参
             * @return 被代理的方法返回值
             * @throws Throwable 异常
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("deleteUser".equals(method.getName())) {
                    // 增强指定方法
                    int id = (int) args[0];
                    id++; //增强参数
                    System.out.println("增强方法体 1/2");
                    String invoke = (String) method.invoke(target, id);
                    invoke = invoke + "!!!"; //增强返回值
                    System.out.println("增强方法体 2/2");
                    return invoke;

                } else {
                    // 其它方法默认实现
                    Object invoke = method.invoke(target, args);
                    return invoke;
                }
            }
        });
    }
}

4. 测试

@Test
public void test01() {
    // 创建目标对象
    UserService target = new UserService();
    System.out.println(target.getClass());
    // 创建代理对象
    IUserService proxy = (IUserService) new ProxyFactory(target).createProxyInstance();
    System.out.println(proxy.getClass());
    // 使用代理对象调用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 

 四 CGLIB代理(子类代理)

通过在内存中构建一个子类对象从而实现对目标对象功能的扩展 CGLIB是一个强大的高性能的代码生成包 底层使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类

优点: 在不修改目标对象的功能前提下 对目标功能扩展 代理对象与目标对象都不需要实现接口

缺点: 需要引入CGLIB的JAR文件

1. 目标对象

/**
 * 目标对象
 * Created by Hy on 2020/7/10.
 */
public class UserService {

    public void insertUser() {
        System.out.println("insert ok");
    }

    public String deleteUser(int id) {
        System.out.println("delete... ... ...");
        return "id = " + id + " delete ok";
    }
}

2. 代理工厂

/**
 * 代理工厂
 * Created by Hy on 2020/7/13.
 */
public class ProxyFactory {

    private Object target; //目标对象

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

    public Object createProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 代理对象调用的所有方法都会触发该方法执行
             * @param proxy 代理对象
             * @param method 被代理的方法
             * @param args 被代理的方法传参
             * @param methodProxy 代理的方法
             * @return 被代理的方法返回值
             * @throws Throwable 异常
             */
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if ("deleteUser".equals(method.getName())) {
                    // 增强指定方法
                    int id = (int) args[0];
                    id++; //增强参数
                    System.out.println("增强方法体 1/2");
                    String invoke = (String) method.invoke(target, id);
                    invoke = invoke + "!!!"; //增强返回值
                    System.out.println("增强方法体 2/2");
                    return invoke;

                } else {
                    // 其它方法默认实现
                    Object invoke = methodProxy.invokeSuper(proxy, args); //等同 method.invoke(target, args);
                    return invoke;
                }
            }
        });
        return enhancer.create();
    }
}

3. 测试

@Test
public void test01() {
    // 创建目标对象
    UserService target = new UserService();
    System.out.println(target.getClass());
    // 创建代理对象
    UserService proxy = (UserService) new ProxyFactory(target).createProxyInstance();
    System.out.println(proxy.getClass());
    // 使用代理对象调用方法
    proxy.insertUser();
    String s = proxy.deleteUser(1);
    System.out.println(s);
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!