1 overview
1.1 the sample
At the most basic level, after creating the business interface and implementation classes, configure < AOP :config>…. The
tag specifies < AOP :pointcut and < AOP: Advisor. The following is an example:
1.1.1 Creating interfaces and implementation classes
Interface:
public interface MockService {
public String hello(String s);
}
Copy the code
Implementation class:
public class MockServiceImpl implements MockService {
@Override
public String hello(String s) {
System.out.println("execute hello");
returns; }}Copy the code
1.1.2 Implement method interception
Implementing an interface org. Aopalliance. Intercept. MethodInterceptor
public class CustomInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("CustomInterceptor before");
Object result = invocation.proceed();
System.out.println("CustomInterceptor after");
returnresult; }}Copy the code
1.1.3 configuration XML
Create aop.xml and place it in the Resources directory:
<?xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
default-lazy-init="false" default-autowire="byName">
<! - implementation to org. Aopalliance. Intercept. MethodInterceptor interceptors -- -- >
<bean id="customInterceptor" class="com.xxx.yyy.CustomInterceptor"/>
<bean id="mockService" class="com.xxx.yyy.MockServiceImpl"/>
<aop:config proxy-target-class="true">
<aop:pointcut id="interceptorPointCuts" expression="execution(* com.xxx.yyy.. *. * (..) )"/>
<aop:advisor advice-ref="customInterceptor" pointcut-ref="interceptorPointCuts"/>
</aop:config>
</beans>
Copy the code
1.1.4 run
public class Main {
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
MockService mockService = (MockService) context.getBean("mockService");
mockService.hello("mock"); }}Copy the code
Returns:
CustomInterceptor before
execute hello
CustomInterceptor after
Copy the code
1.2 AOP implementation process
Spring environment, in the process of start is called AbstractApplicationContext. Refresh (), AOP implementation process, also is to start from here.
- 1 in
obtainFreshBeanFactory()
During execution, loadaop.xmlAnd according to thenamespacefindaop
The correspondingNamespaceHandler:AopNamespaceHandler
; - 2
AopNamespaceHandler
, found inconfigLabel correspondingBeanDefinitionParserThat is, the implementation object ofConfigBeanDefinitionParser
; - 3 perform
ConfigBeanDefinitionParser.parse
, has two functions:- In order to
AspectJAwareAdvisorAutoProxyCreator
Registered BeanDefinition; - parsing
pointcut
.advisor
And register the related object as a BeanDefinition.
- In order to
- 4 Register BeanPostProcessor:
AspectJAwareAdvisorAutoProxyCreator
Is an implementation class for BeanPostProcessorAbstractAutoProxyCreator
The subclass. After registering with BeanPostProcessor,AspectJAwareAdvisorAutoProxyCreator
Is called during Spring’s proxy creation of the bean. - 5. Create proxy and enhance it with Advisor.
- Create a proxy;
- Find matching advisors;
- Enhance the agent.
2 AopNamespaceHandler
Spring environment load, you need to call AbstractApplicationContext. Refresh ().
The refresh () method, execution ConfigurableListableBeanFactory the beanFactory = obtainFreshBeanFactory (); When the BeanFacotry is created, the XML resource is loaded and parsed.
In the process, will call BeanDefinitionParserDelegate. ParseCustomElement extend tags parsing:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
/ / get the namespace
String namespaceUri = getNamespaceURI(ele);
Handlers fetch the corresponding NamespaceHandler according to the meta-INF /spring.handlers file
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// Call the namespaceHandler. parse method to return BeanDefinition
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
Copy the code
For details, please refer to the source code analysis and implementation of Spring custom tag configuration.
For
: in the AopNamespaceHandler registerBeanDefinitionParser (” config “, new ConfigBeanDefinitionParser ());
So:
aop
The parse class for namespace isAopNamespaceHandler
<aop:config/>
The parse class for the tag isConfigBeanDefinitionParser
In theConfigBeanDefinitionParser
,<aop:config/>
The individual elements defined are resolved toBeanDefinition
。
3 ConfigBeanDefinitionParser
ConfigBeanDefinitionParser BeanDefinitionParser interface is achieved, the parse (Element Element, ParserContext ParserContext) method, to realize the function of two parts:
- 1 Register a BeanDefinition with the Spring environment:
AspectJAwareAdvisorAutoProxyCreator
; - 2 Parse XML configuration pointcuts, advisors, and so on into a series of Beandefinitions.
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
/ / registered AspectJAwareAdvisorAutoProxyCreator of BeanDefinition
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
/ / parsing pointcut
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
/ / advisor
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
Copy the code
Among them:
private static final String POINTCUT = "pointcut";
private static final String ADVISOR = "advisor";
private static final String ASPECT = "aspect";
Copy the code
3.1 AspectJAwareAdvisorAutoProxyCreator
3.1.1 role
AspectJAwareAdvisorAutoProxyCreator
isAbstractAutoProxyCreator
The subclass.- Abstractautoxycreator implements the interface
BeanPostProcessor
; - AbstractAutoProxyCreator in
postProcessAfterInitialization
In the implementation of thewrapIfNecessary
Do bean proxying.
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if(bean ! =null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code
Spring calls BeanPostProcessor to process beans before and after they are generated during bean instantiation. Aop takes advantage of this:
Call AbstractAutoProxyCreator postProcessAfterInitialization method, according to the pointcut find corresponding advisor, agent on the bean.
3.1.2 registered BeanDefinition
Code execution flow:
-
1 ConfigBeanDefinitionParser.configureAutoProxyCreator;
-
2 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { / / register BeanDefinition BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); / / set the class - proxy useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); } Copy the code
-
3 AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary;
-
4 AopConfigUtils.registerOrEscalateApcAsRequired:
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
//// omit code
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
Copy the code
The resulting AspectJAwareAdvisorAutoProxyCreator BeanDefinition, BeanName is org. Springframework. Aop. Config. InternalAutoProxyCreator.
At the same time, useClassProxyingIfNecessary method, according to * * aop: proxy in the config / * * – target – class, A parent class set up AspectJAwareAdvisorAutoProxyCreator ProxyConfig proxyTargetClass attributes.
3.2 analytical pointcut
3.2.1 parsePointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
Expression ="execution(* com.xxx.yyy.. *. * (..) )"
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
/ / using AspectJExpressionPointcut, create BeanDefinition for pointcut,
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
/ / id as beanName registered AspectJExpressionPointcut of beans.
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
/ / to automatically generate beanName registered AspectJExpressionPointcut of beans.
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
Copy the code
3.2.2 createPointcutDefinition
- 1
aop:pointcut
Resolve toAspectJExpressionPointcut
Object. - 2
AspectJExpressionPointcut extends AbstractExpressionPointcut
- 3
expression
isAbstractExpressionPointcut
The properties of the
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;
}
Copy the code
3.3 analytical advisor
< AOP :advisor advisor-ref =”customInterceptor” pointcut =”interceptorPointCuts”/> Registered DefaultBeanFactoryPointcutAdvisor BeanDefinition.
3.3.1 parseAdvisor
- 1 call
createAdvisorBeanDefinition
Create the advisor; - 2 call
parsePointcutProperty
For pointcut.
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
/ / 1 create bean: DefaultBeanFactoryPointcutAdvisor
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
/ / 2 registered bean: DefaultBeanFactoryPointcutAdvisor
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// interceptorPointCuts ="interceptorPointCuts"
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
/ / return a ` pointcut ` structure of BeanDefinition (AspectJExpressionPointcut object), Is set ` DefaultBeanFactoryPointcutAdvisor. Pointcut = pointcut `
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
else if (pointcut instanceof String) {
/ / returns the beanName, set ` DefaultBeanFactoryPointcutAdvisor. Pointcut ` Bean references for a runtime.
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
newAdvisorComponentDefinition(advisorBeanName, advisorDef)); }}finally {
this.parseState.pop(); }}Copy the code
3.3.2 rainfall distribution on 10-12createAdvisorBeanDefinition
- 1 create
DefaultBeanFactoryPointcutAdvisor
BeanDefinition DefaultBeanFactoryPointcutAdvisor isPointcutAdvisor
An implementation of; - 2 parsing
advice-ref
Get the beanName of the advisor’s Bean, the customInterceptor in aOP.xml. - 3
DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor
, the use ofadvice-ref
Set up theadviceBeanName
Property, that is, the precedingcustomInterceptor
.
private static final String ADVICE_BEAN_NAME = "adviceBeanName";
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
/ / create a ` DefaultBeanFactoryPointcutAdvisor ` BeanDefinition;
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
// Parse 'advice-ref' beanName of the Bean that gets advice;
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if(! StringUtils.hasText(adviceRef)) { parserContext.getReaderContext().error("'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
/ / set AbstractBeanFactoryPointcutAdvisor adviceBeanName attributes
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;
}
Copy the code
3.3.3 parsePointcutProperty
- 1 attribute has
pointcut
, use the expression to invoke createPointcutDefinition, after constructing AspectJExpressionPointcut bean returned directly. - 2 Otherwise return
pointcut-ref
The specified bean acts as a Pointcut.
Pointcut takes precedence over pointcut-ref.
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
else if (element.hasAttribute(POINTCUT)) {
/ / attributes have ` pointcut `, createPointcutDefinition expression calls after constructing AspectJExpressionPointcut bean returned directly.
String expression = element.getAttribute(POINTCUT);
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
/ / return BeanDefinition
return pointcutDefinition;
}
else if (element.hasAttribute(POINTCUT_REF)) {
String pointcutRef = element.getAttribute(POINTCUT_REF);
if(! StringUtils.hasText(pointcutRef)) { parserContext.getReaderContext().error("'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
// Returns the beanName of pointcut-ref
return pointcutRef;
}
else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null; }}Copy the code
3.4 BeanDefinitions registered during Parsing
- BeanPostProcessor :
AspectJAwareAdvisorAutoProxyCreator
BeanName isorg.springframework.aop.config.internalAutoProxyCreator
; - Pointcut:
AbstractExpressionPointcut
, the expression attribute is set. - Advisor:
DefaultBeanFactoryPointcutAdvisor
The pointcut property is set toAbstractExpressionPointcut
.
4 registered BeanPostProcessor
In AbstractApplicationContext. Refresh () method, create ConfigurableListableBeanFactory, Performs registerBeanPostProcessors registered BeanPostProcessor with the Spring environment.
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
Copy the code
AspectJAwareAdvisorAutoProxyCreator at this time is added to used for processing bean created BeanPostProcessor list.
The brief process is as follows:
- 1 call
PostProcessorRegistrationDelegate.registerBeanPostProcessors
; - 2 by
beanFactory.getBean(ppName, BeanPostProcessor.class);
Get the List of BeanPostProcessors; - 3 perform
beanFactory.addBeanPostProcessor(postProcessor)
.
5 Create beans and enhance them
5.1 createProxy
Spring to create Bean, is in AbstractAutowireCapableBeanFactory doCreateBean method:
- in
AbstractAutowireCapableBeanFactory.doCreateBean
Call theinitializeBean
:
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); }}Copy the code
- in
initializeBean
In:
if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }Copy the code
applyBeanPostProcessorsAfterInitialization
Perform the BeanPostProcessor. PostProcessAfterInitialization method:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
AbstractAutoProxyCreator.postProcessAfterInitialization
Execute here:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if(bean ! =null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code
- in
wrapIfNecessary
Execute createProxy with advisor in:
// Create proxy if we have advice.
// 1 Find advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 2 Create proxy and enhance it with advisor
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
Copy the code
5.2 Searching for matching Advisors
AbstractAutoProxyCreator getAdvicesAndAdvisorsForBean is an abstract method, by the subclass AbstractAdvisorAutoProxyCreator implementation.
AbstractAdvisorAutoProxyCreator. GetAdvicesAndAdvisorsForBean call findEligibleAdvisors, implement two main processes:
- 1. Obtain candidate advisors;
- 2 Filter out matched advisors.
/* beanClass: the beanName of the bean being proxied */
protected List<Advisor> findEligibleAdvisors(Class
beanClass, String beanName) {
// 1 Get the candidate advisors
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2 Filter out matching advisors
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if(! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;
}
Copy the code
5.2.1 findCandidateAdvisors
Call BeanFactoryAdvisorRetrievalHelper findAdvisorBeans, access to all interface realized the Advisor Bean, main code snippet below:
-
1 find beanName that implements Advisor interface:
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);
-
BeanName = beanName;
List<Advisor> advisors = newLinkedList<>(); . advisors.add(this.beanFactory.getBean(name, Advisor.class)); .return advisors; Copy the code
5.2.2 findAdvisorsThatCanApply
Filter out the matching Advisor, mainly through AopUtils findAdvisorsThatCanApply, call canApply implementation:
public static List<Advisor> findAdvisorsThatCanApply(List
candidateAdvisors, Class
clazz)
{
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<>();
for (Advisor candidate : candidateAdvisors) {
/ / call canApply
if (candidate instanceofIntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); }}booleanhasIntroductions = ! eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
/ / call canApply
if(canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); }}return eligibleAdvisors;
}
Copy the code
5.2.3 requirescanApply
- 1 If the interface is
IntroductionAdvisor
In the judgement, call the IntroductionAdvisor. ClassFilter. Matchs; - 2 If the interface is
PointcutAdvisor
(such as DefaultBeanFactoryPointcutAdvisor created earlier), the first call PointcutAdvisor. ClassFilter. Matches judging, The judgement MethodMatcher again. GetMethodMatcher ().
public static boolean canApply(Advisor advisor, Class<? > targetClass,boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true; }}public static boolean canApply(Pointcut pc, Class<? > targetClass,boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if(! pc.getClassFilter().matches(targetClass)) {return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceofIntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<? >> classes =new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for(Class<? > clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {
if((introductionAwareMethodMatcher ! =null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true; }}}return false;
}
Copy the code
5.3 Enhance the agent with advisor
In AbstractAutoProxyCreator. CreateProxy in implementation:
- 1 create ProxyFactory
- 2 determine proxyTargetClass
- 3 buildAdvisors
- 4 implement getProxy
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);
}
/ / create ProxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
/ / determine proxyTargetClass
if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// buildAdvisors
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
/ / getProxy execution
return proxyFactory.getProxy(getProxyClassLoader());
}
Copy the code
5.3.1 DefaultAopProxyFactory.createAopProxy
Proxyfactory. getProxy requires an AopProxy to implement AopProxy. Creating AopProxy in DefaultAopProxyFactory returns a JdkDynamicAopProxy or a CglibAopProxy.
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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 newJdkDynamicAopProxy(config); }}Copy the code
5.3.2 JdkDynamicAopProxy
JdkDynamicAopProxy implements the Java. Lang. Reflect. InvocationHandler interface, in the invoke (Object proxy, Method Method, the Object [] args) implemented in the proxy. The code snippet is as follows:
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
Copy the code
Call ReflectiveMethodInvocation. Proceed () implementation agent.
5.3.3 ObjenesisCglibAopProxy
ObjenesisCglibAopProxy is a subclass of CglibAopProxy. The proxy logic is implemented in CglibAopProxy.
CglibAopProxy derive Callback array, created DynamicAdvisedInterceptor object.
privateCallback[] getCallbacks(Class<? > rootClass){// omit the code
// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// omit the code
}
Copy the code
DynamicAdvisedInterceptor implements org. Springframework. Additional. Proxy. MethodInterceptor interfaces, perform in the intercept method agent:
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
Copy the code
CglibMethodInvocation is a subclass of ReflectiveMethodInvocation, so is also called ReflectiveMethodInvocation. Proceed () implementation agent.