1. Prepare to create an agent
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//1. Finding Enhancers
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
//2. Creating Agents
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
}
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
//Chapter 6 AOP Search Enhancer has analyzed this step
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors,
TargetSource targetSource) {
//For the creation and processing of proxy classes, it is handed over to ProxyFactory, which only does some preparatory work.
ProxyFactory proxyFactory = new ProxyFactory();
//Get the relevant attributes in the current class
proxyFactory.copyFrom(this);
if (!shouldProxyTargetClass(beanClass, beanName)) {
//Like interface com.lwh.spring.JdkProxy.PersonService
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
for (Class<?> targetInterface : targetInterfaces) {
//Add proxy interface
proxyFactory.addInterface(targetInterface);
}
}
//Encapsulate the interceptor as an enhancer. The type of interceptor here is the enhancer.
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
//And add it to ProxyFactory
proxyFactory.addAdvisor(advisor);
}
//SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@1130520d]
proxyFactory.setTargetSource(targetSource);
//Custom agent, empty implementation, implemented by subclasses
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//Create agent
return proxyFactory.getProxy(this.proxyClassLoader);
}
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<Object>();
if (specificInterceptors != null) {
//Added interceptor
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors != null) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
//Converting Interceptor to Advisor
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
2. Creating Agents
return proxyFactory.getProxy(this.proxyClassLoader);
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
//This function really completes the creation of the agent.
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//Three Conditions Affect Spring's Judgment
//1. Opti property, not recommended for users to use this setting
//2.proxytargetclass attribute, previously analyzed
//3. Is there a proxy interface?
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()) {
//Using JDK dynamic proxy
return new JdkDynamicAopProxy(config);
}
return CglibProxyFactory.createCglibProxy(config);
}
else {
//The target object implements the interface and uses JDK dynamic proxy by default
return new JdkDynamicAopProxy(config);
}
}
3. Acquisition Agent
public Object getProxy(ClassLoader classLoader) {
//The first step is to create the agent, and then to obtain the agent.
return createAopProxy().getProxy(classLoader);
}
public Object getProxy(ClassLoader classLoader) {
//Get the proxy interface, which is actually the dynamic proxy implementation of JDK. It is recommended to review the dynamic proxy of JDK.
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//Return the proxy object
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
The key of JDK dynamic proxy is to implement InvocationHandler method and invoke method, and the JdkDynamicAopProxy here
The InvocationHandler interface is implemented, so there must be an invoke method. Look at Notes < JDK Dynamic Agent > and you can see that the proxy object is obtained.
PersonService personService = ctx.getBean("personService", PersonService.class);
What is actually called here is the sayHello method in the generated proxy class. Look at the figure below. Because it's a note taken before, the package names are inconsistent, but the meaning is obvious. The sayHello method in the proxy class
The invoke method in InvocationHandler is also called. This h object, that is, InvocationHandler, is set in Proxy.newProxyInstance, so the following call is made
The sayHello method first enters the invoke method personService.sayHello() of JdkDynamicAopProxy.
4. Method Call
//Get the proxy object
PersonService personService = ctx.getBean("personService", PersonService.class);
//Method call
personService.sayHello();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
//SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@6986852]
TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null;
try {
//Delete part of the code
Object retVal;
//SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@6986852]
target = targetSource.getTarget();
if (target != null) {
//class com.lwh.spring.JdkProxy.PersonServiceImpl
targetClass = target.getClass();
}
//Get the interceptor chain of the current method
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//If the chain is empty, call the tangent method directly
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
//Encapsulate the interceptor in ReflectiveMethod Invocation to facilitate link calls using its proceed method
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//Execute interceptor chain calls
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
}
return retVal;
}
finally {
}
}
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
//After all enhancement methods are executed, a current Interceptor Index counter is maintained and incremented.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//List interceptors AndDynamicMethod Matchers, which records the enhancement methods to be executed and retrieves the enhancement methods to be executed by subscribing
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}