Spring教程14-AOP动态代理

阅读原文

一、什么是代理设计模式

代理设计模式:为其他对象提供一种代理来控制这个对象的访问,比如:公司现在要去谈一个业务,这个业务的核心功能都是由A员工负责的,但是A不想去接触一些与核心功能无关的事情,所以就将一些辅助工作交由B员工来做,当具体到核心业务时,由B向A转达完成核心功能,那么B就是A的代理。代理又分为静态代理和动态代理,静态代理和动态代理最大的区别是静态代理的代理对象在做事前是已知的,动态代理的代理对象是在做事前动态创建的,废话不说了,下面来看代码。

二、静态代理

根据以上的论述,静态代理就是在谈业务时已经找好了A员工的代理B,直接披挂上阵即可。

1、创建接口UserService.java

public interface UserService {
    /**
     * 保存用户信息
     * @return
     */
    public Boolean insertUser();

    /**
     * 根据id查询用户名
     * @param id
     * @return
     */
    public String queryUserNameById(Long id);
}

2、创建实现类UserServiceImpl.java

public class UserServiceImpl implements UserService{
    @Override
    public Boolean insertUser() {
        return true;
    }

    @Override
    public String queryUserNameById(Long id) {
        //用户数据模拟
        Map<Long, String> userNameMap = new HashMap<>();
        userNameMap.put(1l, "张三");
        userNameMap.put(2l, "李四");
        userNameMap.put(3l, "王五");
        return userNameMap.get(id);
    }
}

3、创建UserServiceImpl的代理类

public class UserServiceImplStaticProxy implements UserService {
    private UserServiceImpl targetObj = new UserServiceImpl();
    @Override
    public Boolean insertUser() {
        System.out.println("******代理**********开启事务****************");
        boolean flag = targetObj.insertUser();
        System.out.println("******代理**********提交事务****************");
        return flag;
    }

    @Override
    public String queryUserNameById(Long id) {
        return targetObj.queryUserNameById(id);
    }
}

4、创建静态代理测试类

public class TestProxy {
    /**
     * 测试静态代理
     */
    @Test
    public void testStaticProxy() {
        UserServiceImplStaticProxy userServiceImplStaticProxy = new UserServiceImplStaticProxy();
        Boolean flag = userServiceImplStaticProxy.insertUser();
        if(flag) {
            System.out.println("用户新增成功!");
        } else {
            System.out.println("用户新增失败!");
        }
        System.out.println("*************************静态代理分割线*******************************");
        String userName = userServiceImplStaticProxy.queryUserNameById(1l);
        System.out.println("id为1的用户名称为:" + userName);
    }
}

5、运行测试结果

******代理**********开启事务****************
******代理**********提交事务****************
用户新增成功!
*************************静态代理分割线*******************************
id为1的用户名称为:张三

由运行结果可知静态代理对象已经可以正常完成辅助业务了(事务开启与关闭)。

三、动态代理基于JDK

6、创建基于JDK的代理工厂

public class ProxyFactoryBaseJdk {
    private Object target;
    public ProxyFactoryBaseJdk(Object target) {
        this.target = target;
    }
    /**
     * 获取代理对象
     * @return
     */
    public Object getProxyInstance() {
        Class clazz = target.getClass();
        Object proxy = Proxy.newProxyInstance(
                clazz.getClassLoader(), //获取目标类的类加载器
                clazz.getInterfaces(), //获取目标类所实现的所有接口
                new InvocationHandler() //执行代理对象方法时触发
                {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //执行结果
                Object result = null;
                //如果是新增需要处理事务
                if(method.getName().equals("insertUser")) {
                    System.out.println("******代理**********开启事务****************");
                    result = method.invoke(target, args);
                    System.out.println("******代理**********提交事务****************");
                } else {
                    //直接执行
                    result = method.invoke(target, args);
                }
                return result;
            }
        });
        return proxy;
    }
}

7、创建基于JDK动态代理测试类

public class TestProxy {
    @Test
    public void testJdkAutoProxy() {
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        ProxyFactoryBaseJdk factoryBaseJdk = new ProxyFactoryBaseJdk(userServiceImpl);
        UserService userServiceProxy = (UserService)factoryBaseJdk.getProxyInstance();
        Boolean flag = userServiceProxy.insertUser();
        if(flag) {
            System.out.println("用户新增成功!");
        } else {
            System.out.println("用户新增失败!");
        }
        System.out.println("*************************Jdk动态代理分割线*******************************");
        String userName = userServiceProxy.queryUserNameById(1l);
        System.out.println("id为1的用户名称为:" + userName);
    }
}

8、运行JDK动态代理测试结果

******代理**********开启事务****************
******代理**********提交事务****************
用户新增成功!
*************************Jdk动态代理分割线*******************************
id为1的用户名称为:张三

由运行结果可知基于JDK的动态代理也能够正常的完成辅助业务了(事务的创建与提交)。

四、动态代理基于CGLIB

9、创建ArticleService.java

public class ArticleService {
    /**
     * 插入文章
     * @return
     */
    public Boolean insertArticle() {
        return true;
    }

    /**
     * 根据文章ID获取文章名称
     * @param id
     * @return
     */
    public String queryArticleNameById(Long id) {
        //文章数据模拟
        Map<Long, String> articleNameMap = new HashMap<>();
        articleNameMap.put(1l, "Spring 实战");
        articleNameMap.put(2l, "Spring boot 实战");
        articleNameMap.put(3l, "Spring cloud 实战");
        return articleNameMap.get(id);
    }
}

10、创建ArticleService方法拦截器

public class ArticleServiceMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //执行结果
        Object result = null;
        //如果是新增需要处理事务
        if(method.getName().equals("insertArticle")) {
            System.out.println("******代理**********开启事务****************");
            result = methodProxy.invokeSuper(o, objects);
            System.out.println("******代理**********提交事务****************");
        } else {
            //直接执行
            result = methodProxy.invokeSuper(o, objects);
        }
        return result;
    }
}

11、创建基于CGLIB的动态代理测试类

public class TestProxy {
    @Test
    public void testCGLIBAutoProxy() {
        ArticleService articleService = new ArticleService();
        ProxyFactoryBaseCGLIB proxyFactoryBaseCGLIB = new ProxyFactoryBaseCGLIB(articleService);
        ArticleService ArticleServiceProxy = (ArticleService)proxyFactoryBaseCGLIB.getProxyInstance();
        Boolean flag = ArticleServiceProxy.insertArticle();
        if(flag) {
            System.out.println("文章新增成功!");
        } else {
            System.out.println("文章新增失败!");
        }
        System.out.println("*************************CGLIB动态代理分割线*******************************");
        String articleName = ArticleServiceProxy.queryArticleNameById(1l);
        System.out.println("id为1的文章名称为:" + articleName);
    }
}

12、运行测试结果

******代理**********开启事务****************
******代理**********提交事务****************
文章新增成功!
*************************CGLIB动态代理分割线*******************************
id为1的文章名称为:Spring 实战

由运行结果可知基于CGLIB的动态代理也能够正常的完成辅助业务了(事务的创建与提交)。
总结一下:
通过以上两种不同的动态代理实现方式,我们很容易发现,其实最大的区别在于基于JDK的动态代理,委托类必须要实现一个接口,JDK动态代理会根据此接口创建一个代理实现类来完成代理业务。
而基于CGLIB的动态代理,委托类不需要实现接口,CGLIB动态代理会根据委托类创建一个子类,由子类完成代理业务,那么不管是动态代理还是静态代理对外貌似代理对象完成了所有的业务,实际上代理对象只完成的是辅助业务核心业务还是由委托类对象完成,Spring的动态代理以上两种方式都支持,只需要配置一下下即可,配置参考之前的文章。

更多最新技术文章,请关注“冰点IT”公众号

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值