与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑实现的,但是会散落到代码的各个部分,难以维护。AOP就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。一般用于日志记录、权限验证、效率检查、事务管理。
实现AOP方式有两种,Aspectj和spring aop。我们这里主要了解spring aop,而spring aop的实现也有两种,借鉴aspectj来实现的,一种是自己本身api。我们常用的就是借鉴aspectj来实现的,然后有xml配置和注解配置方式。
我们前面学到,特定的标签都有相应的命名空间解析类解析,即AopNamespaceHandler
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
在AspectJAutoProxyBeanDefinitionParser类的parse方法中会注册 AnnotationAwareAspectJAutoProxyCreator到是spring容器中,父类实现了InstantiationAwareBeanPostProcessor后置处理器。
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册 AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 对注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
在bean初始化的时候会第一次后置处理器调用,执行父类AbstractAutoProxyCreator的postProcessBeforeInstantiation中会去解析注解@Aspect
//判断是否是Advisor、Advice、AopInfrastructureBean
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
进入到AspectJAwareAdvisorAutoProxyCreator.shouldSkip
protected boolean shouldSkip(Class> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
通过findCandidateAdvisors方法来获取所有的候选 advisor
protected List findCandidateAdvisors() {
// 获得 Advisor 实现类
List advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//处理@Aspect注解类, 解析成Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
创建advisor的逻辑发生在扩展接口中的postProcessBeforeInstantiation,实例化之前执行,如果有自定义的TargetSource指定类,则直接生成代理类,这种情况使用不多,常规代理类还是在中postProcessAfterInitialization创建。
现在我们重点看父类AbstractAutoProxyCreator的postProcessAfterInitialization方法。该方法的主要作用也就是将所有拥有advice的bean重新包装为proxy,会在bean初始化的时候第八次调用后置处理器执行。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
// AOP代理逻辑实现
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
我们现在看一下bean如何被包装为proxy
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是aop基础类或配置不需要代理 直接返回
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
//判断这个Bean是否匹配要生成代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
可以看到Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))就是去创建相应的AOP代理类。
protected Object createProxy(Class> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建proxyFactory,proxy的创建主要在这工厂类实现
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//调用getProxy获取bean对应的proxy
return proxyFactory.getProxy(getProxyClassLoader());
}
在具体看proxyFactory.getProxy(getProxyClassLoader())创建的是什么代理对象,JDKProxy或者CGLIBProxy。这需要根据我们配置的来选择,默认是JDK代理对象。进入JdkDynamicAopProxy.getProxy去生成代理对象
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
接下来我们看JDKProxy代理对象,我们可以看到JdkDynamicAopProxy实现InvocationHandler,所以创建代理对象传的是本身this,那么看本类的invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
//会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法得chain是Empty而已
//获取Advice集合,获取作用在这个方法上的所有拦截器链
List
而拦截的方法真正调用的是执行了invocation.proceed()。
会去创建ConfigBeanDefinitionParser来解析config的标签
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
configureAutoProxyCreator(parserContext, element);
List childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
可以看到pointcut、advisor、aspect都有相应的方法去解析,都会把配置信息封装到类中。
在parseAdvisor(elt, parserContext)中会创建AdvisorBeanDefinition并把信息封装在类中。
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext)
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
// 根据通知类型的不同,分别创建对应的BeanDefinition对象
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
// 为不同的增强通知类,添加统一的属性值
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
// 为不同的增强通知类,添加对应的属性值
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
可以知道根据切入方式的不同,分别创建对应的BeanDefinition对象。
before对应AspectJMethodBeforeAdvice、After对应AspectJAfterAdvice、after-returning对应AspectJAfterReturningAdvice
after-throwing对应AspectJAfterThrowingAdvice、around对应AspectJAroundAdvice。
而跟前面一样AopNamespaceHandler初始化的时候会创建AspectJAutoProxyBeanDefinitionParser,后面的逻辑跟注解方式一样去生成代理对象。
通过配置工厂类来实现aop
xxx
我们知道工厂类返回的对象是调用getObject方法
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
在initializeAdvisorChain方法会根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。
之后会去创建代理对象
getProxy(copy.createAopProxy())
创建代理对象会有两种选择,jdk或者cglib
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// JDK动态代理和Cglib的选择
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。