Spring AOP系列文章: 一 约定游戏

介绍

对于spring来说,IOC容器就是Spring的核心,那么AOP就是Spring中最重要的功能之一了。

对于aop,需要掌握以下方面少时诵诗书所所所所所所所所所所所

  1. 动态代理
  2. AOP的概念术语和约定流程
  3. 如何开发aop、@AspectJ 注解方式和XML方式
  4. 掌握AOP中各类的通知
  5. 如何给aop各类通知传递参数
  6. 掌握多个切面的执行顺序

游戏开始

1. 首先定义一个拦截器 interceptor 接口

public interface Interceptor {
    public void before(Object obj);
    public void after(Object obj);
    public void afterReturning(Object obj);
    public void afterThrowing(Object obj);
}

2. 然后生成编写对应的一个实现类 InterceptorImpl

public class InterceptorImpl implements Interceptor {
    @Override
    public void before(Object obj) {
        System.out.println("准备打印角色信息");
    }

    @Override
    public void after(Object obj) {
        System.out.println("角色信息打印完毕");
    }

    @Override
    public void afterReturning(Object obj) {
        System.out.println("刚刚完成打印功能,一切正常");
    }

    @Override
    public void afterThrowing(Object obj) {
        System.out.println("打印功能执行异常了,请检查一下role是否为null");
    }
}

3. 下面开始约定一个规则

要求我们生成对象必须使用ProxyBeanFactorygetBean方法:

public class ProxyBeanFactory {
    public static<T> T getBean(T obj,Interceptor interceptor){
            return (T) ProxyBeanUtil.getBean(obj,interceptor);
    }
}

我们还需要知道,当我们的对象通过ProxyBeanFactorygetBean方法定义后,会存在下面的约定:

  1. 首先这个Bean必须是实现了某一个接口的对象(即这个对象必须实现一个接口才可以使用这个bean
  2. 当我们调用这个bean的一些实现方法的时候,最先会执行拦截器的 before() 方法
  3. 其次才执行 bean的方法(通过反射的形式来调用 method.invoke()
  4. 执行 bean 方法后,无论是否产生异常,都会执行 after 方法
  5. 如果不产生异常,就执行 afterReturning 方法,产生异常则执行 afterThrowing 方法

这个约定其实跟Spring AOP给我们的约定十分接近,流程图如下:

image

4.开始使用这个约定

根据上面的约定指示,我们生成的bean必须实现一个接口,因此我们可以先定义一个接口

假设我们要实现的是打印一个角色信息的业务,我们可以先定义一个 RoleService 接口

public interface RoleService {
    public void printRole(Role role);
}

然后就可以编写实现类了:

public class RoleServiceImpl implements RoleService {
    @Override
    public void printRole(Role role) {
        System.out.println("["+role.getId()+","+role.getRoleName()+","+role.getNote()+"]");
    }
}

5.开始测试我们约定的流程

 public static void main(String[] args) {
 
        RoleService roleService = new RoleServiceImpl();
        Interceptor interceptor = new InterceptorImpl();

        RoleService proxy = ProxyBeanFactory.getBean(roleService,interceptor);
        Role role = new Role(1L,"role1","role_note1");
        proxy.printRole(role);

        System.out.println("########测试 afterThrowing 方法#################");
        role = null;
        proxy.printRole(role);

    }

输出

准备打印角色信息
[1,role1,role_note1]
角色信息打印完毕
刚刚完成打印功能,一切正常
########测试 afterThrowing 方法#################
准备打印角色信息
角色信息打印完毕
打印功能执行异常了,请检查一下role是否为null

6.解释原因

 可以看到,我们并没有调用我们的拦截器 InterceptorImpl 的任何一个方法,仅仅只是实现了一个拦截器,但是程序就可以按照约定的流程执行下去。

 这是因为,在 getBean() 方法的底层实现中,已经帮我们做好了这一些功能

7.getBean()解密

| 上面这些实现,其实都是基于 动态代理 ,我们实际获取到的 RoleService 对象, 是我们封装过的一个代理对象而已。
package ssm_package7.demo01;

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

public class ProxyBeanUtil implements InvocationHandler {

    private Object target; //被代理对象
    private Interceptor interceptor;  //拦截器

    public static Object getBean(Object obj,Interceptor interceptor){
        ProxyBeanUtil _this = new ProxyBeanUtil();
        _this.target = obj;  //保存被代理对象
        _this.interceptor = interceptor;  //保存拦截器

        //生成代理对象,并绑定代理方法
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                _this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object reObj = null;
        //是否产生异常
        boolean exceptionFlag = false;

        //执行拦截器的before方法
        interceptor.before(target);
        try {
            //反射原有方法
            reObj = method.invoke(target,args);
        }catch (Exception e){
            exceptionFlag = true;
        }finally {
            //执行after方法
            interceptor.after(target);
        }

        if (exceptionFlag){
            interceptor.afterThrowing(target);
        }else {
            interceptor.afterReturning(target);
        }

        return reObj;
    }
}

InvocationHandler:实现JDK代理就必须要实现这个接口的 invoke 方法

流程分析

  1. 我们在调用 getBean 方法的时候,首先保存了我们的被代理对象、拦截器,然后返回包装过的代理对象,同时绑定了 ProxyBeanUtil 的一个实例作为其代理类

这样当代理对象调用方法的时候,就会进入到 ProxyBeanUtilinvoke方法中。

  1. 在invoke方法中,我们就可以按照我们图中约定好的顺序,调用拦截器的方法了。

    | 但由于 动态代理和反射的代码比较抽象,更多的时候框架只会告诉我们流程图和具体的流程方法的配置,
    | 就像我们上面给出的约定,我们只需要通过这个 getbean 方法来获取我们的对象,就可以实现图示顺序的代码
    | 因此,我们可以联想到,Spring是不是也给出了这样类似的约定呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值