Spring系列(六)

系列目录

AOP(一)代理设计模式

0. 引出

当项目业务较多时,代码易出现大量冗余。对于高内聚低耦合的目标,传统的三层架构难以优雅的满足。

比如,一个项目中应用层有各项独立业务。而现在,我们需要给每个业务都新增日志记录、权限认证、事务处理等逻辑功能。显然,直接生硬的将相关功能写在给各业务中不仅会造成代码冗余,还会使业务逻辑不清晰,难以维护。

此时,面向切面的思想应运而生。即,我们可以在各层之间建立一个切面,在切面上完成相应的逻辑功能。但这又会引出另外一个问题,就是如何在不改变原有代码的情况下,增添相应的业务功能。由此引出代理设计模式。

代理的意思,简而言之就是,你不用去做,交给别人去做。代理模式就是一个类代表另一个类的功能。我们创建包含对象的另外一个对象,用以对外提供强化性的接口。


 

1. 静态代理模式

代理者和被代理者实现同一个接口(就有了相同的方法),代理者在被代理者原有的方法里调用被代理者的方法,并进行业务增强。这样,我们不再需要调用被代理者,直接调用代理者即可。

静态设计模式解决了软件分层过程中额外的功能代码侵入模块的问题,将额外的功能代码提取到了代理中进行,
但是静态代理实现的代理者中存在大量重复代码,并没有解决代码重复问题。在真正开发中,包括spring底层,基本不会使用静态代码。

 

2. 动态代理-java内置

在java中提供了动态代理实现的工具类,直接使用该工具类就可以创建出代理者,并且可以通过内置的回调函数指定代理在工作时的执行逻辑,从而实现基于jdk原生api的动态代理机制。

/**
*classLoader:用来生成代理者类的类加载器,通常可以传入被代理者类的类加载器。
*interfaces:要求生成的代理者实现的接口们,通常就是实现和代理者相同的接口,保证具有和代理者相同的方法
*invocationHandler:用来设定回调函数的回调接口,使用者需要写一个类实现此接口,从而实现其中的invoke方法
*在其中编写代码处理代理者调用方法时的回调过程,通常在这里调用真正对象上的方法,并且在方法之前或之后做额外的操作。

*/

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 

/**
*proxy:代理者
*method: 当前调用的方法对象
*args:当前调用的方法的参数数组
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)

    
 
  • 优点:不需要像静态代理一样,将被代理方法都实现一遍,只需要在回调函数中进行处理。
  • 缺点:java的动态代理是通过代理者实现与被代理者相同的接口来保证两者具有相同的方法,
    如果被代理者想要被代理的方法不属于任何接口,则生成的代理者自然无法具有该方法,也就无法实现对该方法的代理。
    也即,java的动态代理机制是基于接口进行的,受制于要代理的方法是否有接口的支持。

 

3. 动态代理-第三方包cglib实现

CGLIB是第三方提供的动态代理实现工具,不管有没有接口都可以实现动态代理。
其原理是生成的动态代理是被代理者的子类,所以代理者具有和父类即被代理者相同的方法,从而实现代理。
这种方式基于继承,不再受制于接口。

public UserService getProxy(){
        //1.创建增强器
        Enhancer enhancer = new Enhancer();
        //2.指定要实现的接口们
        enhancer.setInterfaces(userService.getClass().getInterfaces());
        //3.指定父类
        enhancer.setSuperclass(userService.getClass());
        //4.设置回调函数
        enhancer.setCallback(
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        try{
                            System.out.println("记录日这");
                            System.out.println("控制权限");
                            System.out.println("开启事务");
                            Object retobj = method.invoke(userService, objects);
                            System.out.println("提交事务");
                            return retobj;
                        }catch (Exception e){
                            System.out.println("回滚事务");
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }

                    }
                });

        //5.生产代理者
        UserService proxy = (UserService) enhancer.create();
        return proxy;
    }


对比可知,cglib实现动态代理,需要一步一步自己手动设置,而java内置的动态代理是封装好了的。

  • 优点:无论是否有接口都可以实现动态代理,使用场景基本不受限。
  • 缺点:第三方提供的动态代理机制,不是原生的,需要导入第三方开发包才可以使用。
原文地址:https://www.cnblogs.com/juzhuxiaozhu/p/12817921.html