代理设计模式之动态代理(二)

JDK代理

代理条件:实现统一接口

目标类

public class UserServiceImpl implements UserService {

    /**
     * 目标方法
     * @param user
     * @return
     */
    public int addUser(User user) {
        System.out.println("正在新增User对象到数据库..."+user);
        return 1;
    }
    /**
     * 目标方法
     * @param user
     * @return
     */
    public int updateUser(User user) {
        System.out.println("正在更新User对象到数据库..."+user);
        return 1;
    }
    /**
     * 目标方法
     * @param user
     * @return
     */
    public int deleteUser(User user) {
        System.out.println("正在删除User对象到数据库..."+user);
        return 1;
    }
}

动态代理通过拦截器为目标类生成代理类

public class ObjectInterceptor implements InvocationHandler {
    Transaction tx=new Transaction();
    Object target=null; //目标对象
    public ObjectInterceptor(Object target){
        this.target=target;
    }

    /**
     * 执行拦截的方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        tx.openTx();
        //调用目标对象的目标方法
        Object result=method.invoke(target,args);
        tx.closeTx();
        return result;
    }
}

反射中类method,指代目标方法

method.invoke调用反射中(带有指定参数的指定对象调用此method对象表示的底层方法)

此代理中Object result=method.invoke(target,args);

等同于Object result=method.invoke(userService,args);目标对象中的方法

为通用性,创建通用目标对象,再使用构造方法传入

    Object target=null; //目标对象

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

测试类

public class TestProxy {

    @Test
    public void test1(){

        //拦截器对象
        ObjectInterceptor h=new ObjectInterceptor(new UserServiceImpl());

        // us 本质是代理类对象
        // JDK动态代理:使用JDK动态代理自动生成一个代理类对象  com.sun.proxy.$Proxy4,因为$Proxy4在底层JDK生成的!!!
        UserService us= (UserService)
        Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),UserServiceImpl.class.getInterfaces(),h);

        // addUser 是代理类对象的方法
        int count1 = us.addUser(new User(8989, "老王", "人妻"));
        System.out.println(count1>0?"新增成功":"新增失败");



        System.out.println("----------------------------------------------------------");

        int count2 = us.addUser(new User(8080, "小王", "人妻"));
        System.out.println(count1>0?"更新成功":"更新失败");

        printClass();
    }

    public static void printClass(){
        try {
            //把JDK动态代理生成的代理类的class文件输出到硬盘上,方便观察
            byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy4", UserServiceImpl.class.getInterfaces());
            String path="D:/jdkproxy/" + "$Proxy4.class";
            System.out.println(path);
            //字节输出流
            FileOutputStream out = new FileOutputStream(path);
            out.write(classFile);
            out.close();
            System.out.println("自动生成的代理类class文件输出成功~");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

验证代理的真实存在,使用printClass()将代理类打印到硬盘进行观察
Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),UserServiceImpl.class.getInterfaces(),h);
通过反射中的Proxy类调用方法newProxyInstance创建一个代理类
传入参数 类加载器(UserServiceImpl.class.getClassLoader()),实现接口(UserServiceImpl.class.getInterfaces())

当代理类用UserServiceImpl接收时,报错:类转换异常
代理设计模式之动态代理(二)

体现了多态

CGLIB代理

一个强大的,高性能的代码生成库,被广泛运用于AOP框架
代理主要是通过对字节码的操作,为对象引入间接级别,以控制对象的访问
底层使用ASM(一个短小精悍的字节码操作框架)来操作字节码新生成的类(子类),重写父类中过的方法。

导入依赖

<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2</version>
</dependency>

拦截器

public class ObjectInterceptor implements MethodInterceptor {

    Transaction tx=new Transaction();
    /**
     * 执行拦截的方法
     * @param o
     * @param method
     * @param agrs
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] agrs, MethodProxy methodProxy) throws Throwable {
        tx.openTx();
        //调用目标对象的目标方法,父类
        Object result=methodProxy.invokeSuper(o,agrs);
        tx.closeTx();
        return result;
    }
}

测试类,打印验证代理类

public class TestProxy {

    @Test
    public void test1() throws Exception {

        // 在指定目录下生成CGLIB动态代理类子类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\classcglib123");
        //创建拦截器对象
        ObjectInterceptor interceptor = new ObjectInterceptor();
        //作用通过字节码生成真实类的子类对象
        Enhancer enhancer = new Enhancer();
        //谁是父类UserServiceImpl.class--->子类()
        enhancer.setSuperclass(UserServiceImpl.class);
        //设置子类中方法的拦截器
        enhancer.setCallback(interceptor);
        //生成代理类子类对象  us是UserServiceImpl类的对象嘛?
        UserServiceImpl us = (UserServiceImpl) enhancer.create();

        String name = us.getClass().getName();
        System.out.println(name);


        // addUser 是代理类对象的方法
        int count1 = us.addUser(new User(8989, "老王", "人妻"));
        System.out.println(count1 > 0 ? "新增成功" : "新增失败");

        System.out.println("----------------------------------------------------------");

        int count2 = us.updateUser(new User(8080, "小王", "人妻"));
        System.out.println(count1 > 0 ? "更新成功" : "更新失败");


        System.out.println("=========CGLIB$CALLBACK_0==========");
        //
        Field h = us.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        //暴力反射 CGLIB$CALLBACK_0为私有属性
        h.setAccessible(true);
        Object obj = h.get(us);
        //class com.bruceliu.service.impl.interceptor.ObjectInterceptor 证明CGLIB$CALLBACK_0属性为拦截器
        System.out.println(obj.getClass());
    }

}

逻辑

自动代理生成子类,子类方法调用,子类方法中调用拦截器方法(拦截器中添加事务给功能),拦截器中调用父类方法。

效果

拦截器方法执行时打印事务,调用父类方法输出,再执行事务关闭,最后执行测试类中的输出。

上一篇:Spring-IoC(Inversion of Control )控制反转


下一篇:Spring常见注解