Spring AOP 代理总结:静态代理和动态代理

Spring AOP 代理总结:静态代理和动态代理

原文地址:http://jachindo.top:8090/archives/springaop%E4%BB%A3%E7%90%86%E6%80%BB%E7%BB%93%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86%E5%92%8C%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86

参考:https://mp.weixin.qq.com/s/dLOn23waK4gv-Rp9dC0Kfg

0、作用

***将业务逻辑和系统处理的代码(关闭连接、事务管理、操作日志记录)解耦。***


1、静态代理

自己手动创建Proxy类,并将RealSubject类注入。

image-20200201222845606


2、动态代理 - JDK、Cglib

运行时增强:动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

动态代理主要包含:

JDK动态代理:利用反射接收被代理的类,从而生成代理类Proxy类。被代理的类必须实现一个接口

Cglib动态代理:生成被代理类的子类作为代理类。(所以==被代理类不能被final修饰==)

spring aop会根据被代理类是否实现了某个接口来自动选择动态代理方式


1)JDK动态代理

必须实现一个接口(必须有接口和实现类)

扫描二维码关注公众号,回复: 9347181 查看本文章

目标类接口:

package a_proxy.a_jdk;
public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}

实现类:

package a_proxy.a_jdk;
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("a_proxy.a_jdk addUser()");
    }

    @Override
    public void updateUser() {
        System.out.println("a_proxy.a_jdk updateUser()");

    }

    @Override
    public void deleteUser() {
        System.out.println("a_proxy.a_jdk deleteUser()");

    }
}

切面类:

package a_proxy.b_cglib;
public class MyAspect {
    public void before() {
        System.out.println("鸡首");
    }

    public void after() {
        System.out.println("牛后");
    }
}

工厂类(生成代理类):

package a_proxy.a_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanFactory {

    public static UserService createService() {
        //1目标类
        UserService userService = new UserServiceImpl();
        //2切面类
        MyAspect myAspect = new MyAspect();
        /*
        *3代理类:将目标类(切入点)和切面类(通知)结合--->切面
        *
        * Proxy.newProxyInstance
        *   参数1:loader:类加载器,动态代理类运行时创建,任何类都需要类加载器将其加载到内存。
        *       一般情况:采用当前类.class.getClassLoader();
        *                目标类实例.getClass().getClassLoader();
        *   参数2:interfaces:代理类要实现的所有接口
        *       方式1:目标实例.getClass().getInterfaces() ,注意:只能获得自己的接口,不能获得父元素接口
        *       方式2:new Class[]{UserService.class}
        *   参数3:InvocationHandler:处理类,是一个接口,必须进行实现类,一般采用匿名内部方式.表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler 对象上
        *       提供invoke方法,代理类的每一个方法执行时,都将调用一次invoke
        *           参数1:Object proxy:代理对象
        *           参数2:Method method:代理对象当前执行的方法的描述对象(反射)
        *                   执行方法名:method.getName()
        *                   执行方法:method.invoke(对象,实际参数)
        *           参数3:Object[] args:方法的实际参数
        * */
        UserService proxyService = (UserService) Proxy.newProxyInstance(
                MyBeanFactory.class.getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        //前执行
                        myAspect.before();

                        //执行目标类方法
                        Object obj = method.invoke(userService, args);

                        //后执行
                        myAspect.after();
                        return obj;
                    }
                }
        );

        return proxyService;
    }

}

Proxy.newProxyInstance内部通过反射创建代理对象(实现了某接口)。

每一个动态代理类都必须要实现 InvocationHandler 这个接口,并且每个代理类的实例都关联到了一个 Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler 这个接口的 invoke 方法来进行调用。

测试类:

package a_proxy.a_jdk;

import org.junit.Test;

public class TestJDK {
    @Test
    public void demo1() {
        UserService userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
}

结果:

image-20190528111901900

注意:

通过 Proxy.newProxyInstance 创建的代理对象是在 jvm 运行时动态生成的一个对象,它并不是我们的 InvocationHandler 类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy 为中,最后一个数字表示对象的标号,如com.sun.proxy.$Proxy0


2)Cglib动态代理(字节码增强)

不需要接口,只有实现类

!!!在运行时创建目标类的子类(代理类),从而对目标类进行增强!!!

工厂类:

package a_proxy.b_cglib;
public class MyBeanFactory {

    public static UserServiceImpl createService() {
        //1目标类
        UserServiceImpl userService = new UserServiceImpl();
        //2切面类
        MyAspect myAspect = new MyAspect();

        /*
        * 3 代理类,采用cglib,底层创建目标的子类
        * */
        //3.1核心类
        Enhancer enhancer = new Enhancer();
        //3.2确定父类
        enhancer.setSuperclass(userService.getClass());
        //3.3设置回调 MethodInterceptor接口等效于jdk中的InvocationHandler
        /*
        * intercept()等效于jdk的invoke()
        *       参数1,2,3与invoke的一样
        *       参数4:methodProxy方法的代理,通常不用
        * */
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //前
                myAspect.before();
                //执行目标类的方法
                Object obj = method.invoke(userService, objects);
                //执行代理类的父类,即目标类(目标类和代理类是父子关系)
                //methodProxy.invokeSuper(o, objects);

                //后
                myAspect.after();
                return obj;
            }
        });

        //3.4创建代理
        UserServiceImpl proxyService = (UserServiceImpl)enhancer.create();
        return proxyService;
    }

}

测试类:

package a_proxy.b_cglib;

import org.junit.Test;

public class TestCglib {
    @Test
    public void demo1() {
        UserServiceImpl userService = MyBeanFactory.createService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
}

结果与jdk动态代理相同

发布了28 篇原创文章 · 获赞 16 · 访问量 3192

猜你喜欢

转载自blog.csdn.net/Newbie_J/article/details/101364796