spring aop
源码大约分两步分,第一部分是在spring ioc初始化过程中加载所有aop标签到容器中,绑定代理类生成器AspectJAwareAdvisorAutoProxyCreator。
第二部分是在调用getBean实例化bean后,通过BeanPostProcessor的回调机制生成代理类。
如何使用
@Aspect
public class VocalConcert {
//定义一个切点,下面通知中可以直接使用,避免重复代码
@Pointcut("execution(* com.aop.test1.Song.song(..))")
public void doing() {
}
@Before("doing()")
public void checking() {
System.out.println("检票之后,找位子坐下");
}
@AfterReturning("doing()")
public void beautiful() {
System.out.println("演唱会进入精彩部分的时候,鼓掌!");
}
@AfterReturning("doing()")
public void leave() {
System.out.println("结束后,我们离开场地");
}
}
结合上面代码分析什么叫切面、切点、通知、引入?
切面:被声明为@Aspect的整个类VocalConcert叫做切面。
切点:@Pointcut该注解定义切点,用来指明要拦截的目标类的方法
通知:切面中定义的那些before、after等等逻辑可以叫做通知。
引入:上面涉及到所有的都是对类中方法的增加,引入是对类的增强
通知:通知包括以下几种:
1、前置通知
2、后置通知 在目标方法执行完之后执行
3、返回通知 在目标方法正常返回后执行,如果发生异常,目标方法没有返回,则不执行
4、异常通知
5、环绕通知 前置通知+后置通知
spring支持的4种aop类型:
1、经典spring aop:不在使用
2、AspectJ切面:和spring没有什么关系,AspectJ框架。可以对字段构造器等进行增强。不做深入学习。
3、纯pojo切面:基于aop的命名空间, 在xml中定义切面
4、注解驱动的切面:对纯pojo切面进行改进,不在xml中定义切面,通过声明切面类+注解
关注的是3和4,就是spring中传统的xml和注解两种方式。
纯pojo切面(xml)
1、定义切面类
public class SleepAspect {
public void before(){
System.out.println("睡觉之前拖衣服");
}
public void afterReturning(){
System.out.println("睡觉");
}
public void afterThrowing(Exception ex) throws Exception {
System.out.println("出大事了,有bug");
System.out.println(ex.getMessage());
}
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Object proceed =null;
if (!"".equals("admin")){
System.out.println("核心方法被执行");
proceed = pjp.proceed(pjp.getArgs());
System.out.println("核心方法执行完");
}
return proceed;
}
}
2、声明目标类
3、xml中声明切面
<!--将切面类和目标类都交给spring容器-->
<bean id="sleep" class="com.yztc.pojo.SleepDaoImpl"/>
<bean id="sleepAspect" class="com.yztc.pojo.SleepAspect"/>
<!--配置AOP-->
<aop:config>
<!--切面-->
<aop:aspect id="aspect" ref="sleepAspect">
<!--切入点的配置-->
<aop:pointcut id="pointcut" expression="execution(* com.yztc.pojo.*.Sleep.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
注解驱动的切面
这种方式就是在纯pojo切面基础上通过注解进行改进,不用在xml中声明切面。
1、定义一个切面
@Aspect
public class VocalConcert {
//定义一个切点,下面通知中可以直接使用,避免重复代码
@Pointcut("execution(* com.aop.test1.Song.song(..))")
public void doing() {
}
@Before("doing()")
public void checking() {
System.out.println("检票之后,找位子坐下");
}
@AfterReturning("doing()")
public void beautiful() {
System.out.println("演唱会进入精彩部分的时候,鼓掌!");
}
@AfterReturning("doing()")
public void leave() {
System.out.println("结束后,我们离开场地");
}
}
2、开启切面功能
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" //这里引入aop命名空间
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.aop.test1"/>
<bean class="com.aop.test1.VocalConcert" id="concert"/>
<aop:aspectj-autoproxy/> //开启spring切面功能
</beans>
AopNamespaceHandler
aop自定义标签解析器,用来解析aop自定义标签。
AopNamespaceHandler和aop标签是如何映射的?
xml中aop的命名空间 -- spring aop jar包下的META-INF下的spring.handlers。
AopNamespaceHandler :该类的init方法中绑定了几种aop标签对应的parser
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@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());
}
}
aop标签包含好几种,每一种都对应自己的parser,这种映射关系在上面AopNamespaceHandler的init方法中指定。具体标签包括哪些呢?
<aop:config>
<!--切面-->
<aop:aspect id="aspect" ref="sleepAspect">
<!--切入点的配置-->
<aop:pointcut id="pointcut" expression="execution(* com.yztc.pojo.*.Sleep.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
上面代码中:config、aspect等都属于aop标签。
获取标签解析器
回顾ioc初始化流程,
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {//循环解析所有标签
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);//默认标签
}
else {
delegate.parseCustomElement(ele);//自定义标签
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
//BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
//NamespaceHandlerSupport
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
首先获取标签解析器
因为aop最外层标签是config标签,所以先看下ConfigBeanDefinitionParser的parse方法
ConfigBeanDefinitionParser.parse:
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
//向spring容器注册AspectJAwareAdvisorAutoProxyCreator
configureAutoProxyCreator(parserContext, element);
List<Element> 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;
}
1、向spring容器注册代理类生产器AspectJAwareAdvisorAutoProxyCreator
2、遍历所有aop标签下的所有子节点,分别定义三个入口,切面、切点、通知
解析切面
接下来该解析切面,注意,切面里边包含通知和切点,所以这个方法也包含了通知和切点的解析
ConfigBeanDefinitionParser.parseAspect:遍历所有aop标签,解析相应的通知和切点
private void parseAspect(Element aspectElement, ParserContext parserContext) {
String aspectId = aspectElement.getAttribute(ID);
String aspectName = aspectElement.getAttribute(REF);
try {
this.parseState.push(new AspectEntry(aspectId, aspectName));
List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
List<BeanReference> beanReferences = new ArrayList<BeanReference>();
List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
Element declareParentsElement = declareParents.get(i);
beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
}
//获取切面所有子节点进行遍历
NodeList nodeList = aspectElement.getChildNodes();
boolean adviceFoundAlready = false;
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (isAdviceNode(node, parserContext)) {
if (!adviceFoundAlready) {
adviceFoundAlready = true;
if (!StringUtils.hasText(aspectName)) {
parserContext.getReaderContext().error(
"<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
aspectElement, this.parseState.snapshot());
return;
}
beanReferences.add(new RuntimeBeanReference(aspectName));
}
//如果标签是通知,进入解析通知标签方法
AbstractBeanDefinition advisorDefinition = parseAdvice(
aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
beanDefinitions.add(advisorDefinition);
}
}
AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
parserContext.pushContainingComponent(aspectComponentDefinition);
List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
for (Element pointcutElement : pointcuts) {//获取切面下所有切点标签进行解析
//进入切点标签的解析方法入口
parsePointcut(pointcutElement, parserContext);
}
parserContext.popAndRegisterContainingComponent();
}
finally {
this.parseState.pop();
}
}
该方法拿到切面下所有的切点和通知标签进行遍历解析。切点调用parsePointcut解析,通知调用parseAdvice解析。
解析通知
//ConfigBeanDefinitionParser
private AbstractBeanDefinition parseAdvice(
String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
try {
this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
// create the method factory bean
RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
methodDefinition.setSynthetic(true);
// create instance factory definition
RootBeanDefinition aspectFactoryDef =
new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
aspectFactoryDef.setSynthetic(true);
// 声明通知为BeanDefinition
AbstractBeanDefinition adviceDef = createAdviceDefinition( //入口
adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
beanDefinitions, beanReferences);
// 对上面创建的BeanDefinition包装一下
RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(adviceElement));
advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
}
// register the final advisor
parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
return advisorDefinition;
}
finally {
this.parseState.pop();
}
}
private AbstractBeanDefinition createAdviceDefinition(
Element adviceElement, ParserContext parserContext, String aspectName, int order,
RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
//入口
RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
adviceDefinition.setSource(parserContext.extractSource(adviceElement));
adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
if (adviceElement.hasAttribute(RETURNING)) {
adviceDefinition.getPropertyValues().add(
RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
}
if (adviceElement.hasAttribute(THROWING)) {
adviceDefinition.getPropertyValues().add(
THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
}
if (adviceElement.hasAttribute(ARG_NAMES)) {
adviceDefinition.getPropertyValues().add(
ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
}
ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);
Object pointcut = parsePointcutProperty(adviceElement, parserContext);
if (pointcut instanceof BeanDefinition) {
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
beanDefinitions.add((BeanDefinition) pointcut);
}
else if (pointcut instanceof String) {
RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
beanReferences.add(pointcutRef);
}
cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);
return adviceDefinition;
}
private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
String elementName = parserContext.getDelegate().getLocalName(adviceElement);
if (BEFORE.equals(elementName)) {
return AspectJMethodBeforeAdvice.class;
}
else if (AFTER.equals(elementName)) {
return AspectJAfterAdvice.class;
}
else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
return AspectJAfterReturningAdvice.class;
}
else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
return AspectJAfterThrowingAdvice.class;
}
else if (AROUND.equals(elementName)) {
return AspectJAroundAdvice.class;
}
else {
throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
}
}
该方法为每个通知实例化一个bean到spring容器。
不同类型的通知生成的RootBeanDifination的class属性不同
解析切点
//ConfigBeanDefinitionParser
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
//将pointcut创建成一个BeanDefinition
pointcutDefinition = createPointcutDefinition(expression);//入口
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
为每个切点实例化一个bean到spring容器
代理类的创建
到这里,在ioc启动过程中,通过aop解析器把aop标签声明成BeanDefinition到spring容器中,已经完毕。
同时注意上面注册了一个类AspectJAwareAdvisorAutoProxyCreator,该类是BeanPostProcessor的下层类,同时封装了为普通bean生成代理类的方法。
这就意味着,在调用getBean获取bean实例之后,通过BeanPostProcessor的回调机制,通过spring容器中的相关aop标签和AspectJAwareAdvisorAutoProxyCreator类就可以创建代理类。
BeanPostProcessor回调为入口:
//AbstractAutoProxyCreator
@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;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
//判断是否需要生成代理类
//入口1
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(//入口2 生成代理的方法
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
/***
* findEligibleAdvisors方法是拿当前Advisor对应的expression做了两层判断:
*
* 目标类必须满足expression的匹配规则
* 目标类中的方法必须满足expression的匹配规则,当然这里方法不是全部需要满足expression的匹配规则,有一个方法满足即可
*/
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
1、根据bean名称去spring容器获取所有的asvisor,注意:这个advisor包含切面和通知
2、匹配切点规则是否满足这个类,如果满足调用createProxy创建代理类
接下来就是创建代理类的方法
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 1.创建proxyFactory,proxy的生产主要就是在proxyFactory做的
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//<aop:config>这个节点中proxy-target-class="false"或者proxy-target-class不配置,即不使用CGLIB生成代理。
// 如果满足条件,进判断,获取当前Bean实现的所有接口,讲这些接口Class对象都添加到ProxyFactory中。
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 3.调用getProxy获取bean对应的proxy
return proxyFactory.getProxy(getProxyClassLoader());//入口
}
1、创建代理类工厂
2、将所有满足条件的advisor bean添加到代理工厂中
3、通过代理工厂创建代理类
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);//入口1 + 入口2
}
1、通过createAopProxy选择是jdk还是cglib
2、通过getProxy创建代理类
// createAopProxy()方法就是决定究竟创建何种类型的proxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 1.ProxyConfig的isOptimize方法为true,这表示让Spring自己去优化而不是用户指定
// 2、ProxyConfig的isProxyTargetClass方法为true,这表示配置了proxy-target-class="true"
// 3、ProxyConfig满足hasNoUserSuppliedProxyInterfaces方法执行结果为true,
// 这表示<bean>对象没有实现任何接口或者实现的接口是SpringProxy接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
// 2.如果目标类是接口或者是代理类,则直接使用JDKproxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 3.其他情况则使用CGLIBproxy
return new ObjenesisCglibAopProxy(config);
} else {
return new JdkDynamicAopProxy(config);
}
}
如果配置了就按照配置的选择,如果目标类是接口直接使用jdk代理
以jdk动态代理为例继续走下去。
public Object getProxy(ClassLoader classLoader) {
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// JDK proxy 动态代理的标准用法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
jdk动态代理创建。
执行目标方法
我们知道,jdk动态代理通过代理类调用目标方法的时候,实际调用的是自定义拦截器的invoke方法,aop的自定义拦截器为JdkDynamicAopProxy。
//知道,jdk动态代理通
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//没有拦截器的时候,进入这个方法,直接通过反射调用目标方法
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);//入口1
}
Object retVal;
if (this.advised.exposeProxy) {//将代理类暴漏到AopContext中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取目标对象
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取拦截器链 advisor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//入口3
if (chain.isEmpty()) {
// 如果拦截器为空,那么直接调用目标对象的目标方法 进入该方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 否则,需要先调用拦截器然后再调用目标方法,通过构造一个ReflectiveMethodInvocation来实现
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 沿着拦截器链前行 进入该方法
retVal = invocation.proceed();//入口2
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
}
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable {
ReflectionUtils.makeAccessible(method);
// 通过反射的方式直接调用目标对象方法
return method.invoke(target, args);
}
@Override
public Object proceed() throws Throwable {
// 从索引为-1的拦截器开始调用,按顺序递增,直到没有拦截器了,然后开始调用目标对象的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 沿着定义好的拦截器链进行获取然后逐个处理
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 这里是触发匹配判断的地方,如果和定义的pointcut匹配,那么这个advice将得到执行
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
else {
// 如果是一个interceptor,那么直接调用这个interceptor的invoke方法 进入此方法来分析通知(拦截器)是如何起作用的
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// 所有的advistor在config中已经持有了,可以直接使用
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//通过AdvisorAdapterRegistry注册器,把从config中获取的advistor进行适配,从而获得拦截器,再把它放入List中。这就是拦截器注册的过程。
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
- 将所有的通知封装成一个拦截器链表,然后按顺序执行,最后通过反射调用目标方法
- AopContext内部通过ThreadLocal来存储了代理类,如果expose-proxy属性开启,这里还没将代理类放入到AopContext中。