什么是AOP
AOP(Aspect-Oriented Programming),即面向切面编程,用人话说就是把公共的逻辑抽出来,让开发者可以更专注于业务逻辑开发。
和IOC一样,AOP也指的是一种思想。AOP思想是OOP(Object-Oriented Programming)的补充。OOP是面向类和对象的,但是AOP则是面向不同切面的。一个切面可以横跨多个类和对象去操作,极大的丰富了开发者的使用方式,提高了开发效率。
譬如,一个订单的创建,可能需要以下步骤:
- 权限校验
- 事务管理
- 创建订单
- 日志打印
如果使用AOP思想,我们就可以把这四步当成四个“切面”,让业务人员专注开发第三个切面(业务),其他三个切面则是基础的通用逻辑,统一交给AOP封装和管理。
我们来看如下代码:
@Service public class OrderService { public void createOrder(Order order) { // 创建订单逻辑 // ... System.out.println("Order created."); } }
@Component @Aspect public class OrderAspect { //前置权限校验逻辑 @Before("execution(* com.example.service.OrderService.createOrder(..))") public void checkPermission(JoinPoint joinPoint) { // 权限校验逻辑 // ... System.out.println("Permission checked."); } //中间在事务内执行核心业务逻辑 @Around("execution(* com.example.service.OrderService.createOrder(..))") public Object manageTransaction(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { try { // 开启事务 // ... // 执行目标方法 Object result = proceedingJoinPoint.proceed(); // 提交事务 // ... return result; } catch (Exception e) { // 回滚事务 // ... throw e; } } //后置日志记录逻辑 @AfterReturning("execution(* com.example.service.OrderService.createOrder(..))") public void logAfterReturning(JoinPoint joinPoint) { // 日志打印逻辑 // ... System.out.println("订单创建成功。日志记录完成!"); } }
当业务人员调用 OrderService
的 createOrder
方法时,AOP会自动将切面中的逻辑织入到该方法的前、中、后各个阶段,完成权限校验、事务管理和日志打印的功能。
Spring AOP有如下概念
对于通知类型来说:
补充:
AOP是如何实现的
从Bean的初始化流程中来讲,Spring的AOP会在bean实例的实例化已完成,进行初始化后置处理时创建代理对象,即下面代码中的applyBeanPostProcessorsAfterInitialization部分。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { //... //检查Aware invokeAwareMethods(beanName, bean); //调用BeanPostProcessor的前置处理方法 Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //调用InitializingBean的afterPropertiesSet方法或自定义的初始化方法及自定义init-method方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } //调用BeanPostProcessor的后置处理方法 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
applyBeanPostProcessorsAfterInitialization中会遍历所有BeanPostProcessor,然后
调用其postProcessAfterInitialization方法,而AOP代理对象的创建就是AbstractAutoProxyCreator这个类的postProcessAfterInitialization方法中
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
这里面最重要的就是wrapIfNecessary方法了:
/** * 如果需要,对bean进行包装。 * * @param bean 要包装的目标对象 * @param beanName bean的名称 * @param cacheKey 缓存键 * @return 包装后的对象,可能是原始对象或代理对象 */ protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 如果beanName不为null且在目标源bean集合中,则直接返回原始对象 if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } // 如果缓存键对应的值为Boolean.FALSE,则直接返回原始对象 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 如果bean的类型为基础设施类,或者应跳过该类型的代理,则将缓存键对应的值设置为Boolean.FALSE并返回原始对象 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 如果存在advice,为bean创建代理对象 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { // 将缓存键对应的值设置为Boolean.TRUE this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 将代理对象的类型与缓存键关联起来 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 如果没有advice,将缓存键对应的值设置为Boolean.FALSE并返回原始对象 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
createProxy的主要作用是根据给定的bean类、bean名称、特定拦截器和目标源,创建代理对象:
/** * 根据给定的bean类、bean名称、特定拦截器和目标源,创建代理对象。 * * @param beanClass 要代理的目标对象的类 * @param beanName bean的名称 * @param specificInterceptors 特定的拦截器数组 * @param targetSource 目标源 * @return 创建的代理对象 */ protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { // 如果beanFactory是ConfigurableListableBeanFactory的实例,将目标类暴露给它 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建ProxyFactory实例,并从当前代理创建器复制配置 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); // 如果不强制使用CGLIB代理目标类,根据条件决定是否使用CGLIB代理 if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 根据bean类评估代理接口 evaluateProxyInterfaces(beanClass, proxyFactory); } } // 构建advisor数组 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 将advisors添加到ProxyFactory中 proxyFactory.addAdvisors(advisors); // 设置目标源 proxyFactory.setTargetSource(targetSource); // 定制ProxyFactory customizeProxyFactory(proxyFactory); // 设置代理是否冻结 proxyFactory.setFrozen(this.freezeProxy); // 如果advisors已经预过滤,则设置ProxyFactory为预过滤状态 if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 获取代理对象,并使用指定的类加载器 return proxyFactory.getProxy(getProxyClassLoader()); }
Spring AOP 是通过代理模式实现的。
具体有两种实现方式,一种是基于Java原生的动态代理,一种是基于cglib的动态代理。对应到代码中就是,这里面的Proxy有两种实现,分别是CglibAopProxy和JdkDynamicAopProxy。
Spring AOP默认使用标准的JDK动态代理进行AOP代理。
这使得任何接口可以被代理。但是JDK动态代理有一个缺点,就是它不能代理没有接口的类。
所以Spring AOP就使用CGLIB代理没有接口的类。