java 基本知识之代理

2019-12-27  本文已影响0人  瀚海网虫

1. 静态代理

简言之
代理对象 = 增强代码+ 目标对象(原对象)

/**
 * 快递员
 */
public class Courier implements IBuy{
    @Override
    public void buy() {
        System.out.println("买一瓶药");
    }
}
public interface IBuy {
    void buy();
}
public class SFCourierProxy {
    // 接收目标对象,以便调用buy方法
    private IBuy courier;
    public SFCourierProxy(IBuy courier) {
        this.courier = courier;
    }
    // 对目标对象的buy方法进行功能扩展
    public void buy() {
        System.out.println("所有的药都来自大药店");
        courier.buy();
        System.out.println("药买好后,将会第一时间送到您身边");
    }
}
public class TestProxy {
    public static void main(String[] args) {=
        IBuy courier = new Courier();
        SFCourierProxy sfCourierProxy = new SFCourierProxy(courier);
        sfCourierProxy.buy();
    }
}

输出结果

所有的药都来自大药店
买一瓶药
药买好后,将会第一时间送到您身边

1.1 优点

  1. 不直接操作原对象,隔离性好
  2. 增加原对象功能,修饰或者新增功能方便

1.2 缺点

  1. 代理对象通常与原对象是1对1关系(当然也可以是1对多),如果需要被代理
  2. 的对象多,会导致代理类激增,带来冗余与增加维护成本。
  3. 被代理类发生改变时,代理类也需要改变

2. 动态代理

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在Jvm的方法区内,然后在区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

image.png

类对象的创建过程


image.png image.png

Java 中的所有类型包括基本类型(int, long, float等等),即使是数组都有与之关联的 Class 类的对象。

Class对象是由Jvm自动生成的,每当一个类被载入时,Jvm就自动为其生成一个Class对象

作者:dsying
链接:https://juejin.im/post/5dac4edff265da5b5f7588d1
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

两个核心类:Proxy 与 InvocationHandler

public interface UserService {
    public void select();
    public void update();
}
public class UserServiceImpl implements UserService {
    @Override
    public void select() {
        System.out.println("查询 selectById");
    }
    @Override
    public void update() {
        System.out.println("更新 update");
    }
}
public class LogDynamicProxy implements InvocationHandler {
    Object target;  // 被代理的对象,实际的方法执行者

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object object = method.invoke(target, args);
        end();
        return object;
    }

    private void before() {
        System.out.println(String.format("log start time [%s]",new Date()));
    }

    private void end() {
        System.out.println(String.format("log end time [%s]",new Date()));
    }
}
public class LogDynamicProxy2 implements InvocationHandler {
    ....
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
}
public class DynamicProxyTest {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        LogDynamicProxy logHandler = new LogDynamicProxy(userService);

        UserService userService1 = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),logHandler);

        userService1.select();
        userService1.update();

        LogDynamicProxy2 logHandler2 = new LogDynamicProxy2(userService);
        UserService userService2 = logHandler2.getProxy();
        userService2.select();
        userService2.update();
    }
}
public class DynamicProxyTest {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        LogDynamicProxy logHandler = new LogDynamicProxy(userService);

        UserService userService1 = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),logHandler);
        System.out.println("--代理1形式---");
        userService1.select();
        userService1.update();
        
        System.out.println("--代理2形式---");
        LogDynamicProxy2 logHandler2 = new LogDynamicProxy2(userService);
        UserService userService2 = logHandler2.getProxy();
        userService2.select();
        userService2.update();
    }
}
--代理1形式---
log start time [Fri Dec 27 11:23:47 CST 2019]
查询 selectById
log end time [Fri Dec 27 11:23:47 CST 2019]
log start time [Fri Dec 27 11:23:47 CST 2019]
更新 update
log end time [Fri Dec 27 11:23:47 CST 2019]
--代理2形式---
log start time [Fri Dec 27 11:23:47 CST 2019]
查询 selectById
log end time [Fri Dec 27 11:23:47 CST 2019]
log start time [Fri Dec 27 11:23:47 CST 2019]
更新 update
log end time [Fri Dec 27 11:23:47 CST 2019]

除了 Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),logHandler);
还有另一种创建方法 constructor.newInstance(new InvocationHandler()

public class ProxyTest2 {
    public static void main(String[] args) throws Exception{
       UserService userService = new UserServiceImpl();
       UserService userService1 = (UserService) getProxy(userService);
        userService1.select();
        userService1.update();
    }
    private static Object getProxy(Object object) throws Exception  {
        Class calculatorProxyClazz = Proxy.getProxyClass(UserService.class.getClassLoader(), UserService.class);
        Constructor constructor = calculatorProxyClazz.getConstructor(InvocationHandler.class);
        UserService proxy = (UserService) constructor.newInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("开始执行方法");
                UserService userService1 = new UserServiceImpl();
                Object result = method.invoke(userService1, args);
                System.out.println("方法名" + method) ;
                System.out.println("执行方法结束");
                return result;
            }
        });
        return proxy;
    }
}

2.1 优点

  1. 动态生成代理对象,解决代理类泛滥问题
  2. 被代理类发生改变时,被代理类不需要改变

2.2 缺点

无论静态代理还是动态代理,都需要一个接口。
如果要包装的防范,没有实现接口怎么办呢?

3.CGLib 动态代理

CGLib 是一个类库,它可以在运行期间动态的生成字节码,动态生成代理类。

上一篇下一篇

猜你喜欢

热点阅读