文章目录
介绍
对于spring来说,IOC容器就是Spring的核心,那么AOP就是Spring中最重要的功能之一了。
对于aop,需要掌握以下方面少时诵诗书所所所所所所所所所所所
- 动态代理
- AOP的概念术语和约定流程
- 如何开发aop、@AspectJ 注解方式和XML方式
- 掌握AOP中各类的通知
- 如何给aop各类通知传递参数
- 掌握多个切面的执行顺序
游戏开始
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. 下面开始约定一个规则
要求我们生成对象必须使用ProxyBeanFactory的getBean方法:
public class ProxyBeanFactory {
public static<T> T getBean(T obj,Interceptor interceptor){
return (T) ProxyBeanUtil.getBean(obj,interceptor);
}
}
我们还需要知道,当我们的对象通过ProxyBeanFactory的getBean方法定义后,会存在下面的约定:
- 首先这个Bean必须是实现了某一个接口的对象(即这个对象必须实现一个接口才可以使用这个bean)
- 当我们调用这个bean的一些实现方法的时候,最先会执行拦截器的 before() 方法
- 其次才执行 bean的方法(通过反射的形式来调用 method.invoke())
- 执行 bean 方法后,无论是否产生异常,都会执行 after 方法
- 如果不产生异常,就执行 afterReturning 方法,产生异常则执行 afterThrowing 方法
这个约定其实跟Spring AOP给我们的约定十分接近,流程图如下:
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 方法
流程分析:
- 我们在调用 getBean 方法的时候,首先保存了我们的被代理对象、拦截器,然后返回包装过的代理对象,同时绑定了 ProxyBeanUtil 的一个实例作为其代理类
这样当代理对象调用方法的时候,就会进入到 ProxyBeanUtil的invoke方法中。
-
在invoke方法中,我们就可以按照我们图中约定好的顺序,调用拦截器的方法了。
| 但由于 动态代理和反射的代码比较抽象,更多的时候框架只会告诉我们流程图和具体的流程方法的配置,
| 就像我们上面给出的约定,我们只需要通过这个 getbean 方法来获取我们的对象,就可以实现图示顺序的代码
| 因此,我们可以联想到,Spring是不是也给出了这样类似的约定呢?