Code address: github.com/mxsm/spring…

Phenomenon of 1.

The first case:

The second case:

The third case:

2. Symptom Description

The first is the most common. In normal Spring applications, you will find that neither UserService nor TeacherService created an agent. This is the most common way to use it.

The second option is to start Spring AOP with the @EnableAspectJAutoProxy annotation and find that UserService** uses the JDK proxy and TeacherService uses the CGLIB proxy

UserService and TeacherService are using the CGlib proxy. The CGlib proxy is used by UserService and TeacherService

No proxy is created without AOP enabled. With the @enableAspectJAutoProxy default, the interface proxy uses JDK proxy implementation and the class proxy uses CGLIB (JDK does not implement class proxy). @enableAspectJAutoProxy (proxyTargetClass = true) enforces the CGLIB proxy.

3. Source code analysis

3.1 Proxy classes will be used above

As you can see from the previous Spring AOP source code parsing, the main classes of AOP created in annotation mode are: AnnotationAwareAspectJAutoProxyCreator, this class overrides the initBeanFactory and findCandidateAdvisors two methods:

InitBeanFactory method:

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	super.initBeanFactory(beanFactory);
	if (this.aspectJAdvisorFactory == null) {
		this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
	}
	this.aspectJAdvisorsBuilder =
			new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
Copy the code

Function:

  • The new ReflectiveAspectJAdvisorFactory

  • The new BeanFactoryAspectJAdvisorsBuilderAdapter

    Use to build the Bean that contains the @Aspect annotation into an Advisor

findCandidateAdvisors:

@Override
protected List<Advisor> findCandidateAdvisors(a) {
	// Add all the Spring advisors found according to superclass rules.
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	if (this.aspectJAdvisorsBuilder ! =null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}
Copy the code

Function:

  • Find candidate Advisors (those that implement the Advisor interface)
  • Build AspectJ as Advisor(@aspec, @before, etc. related Aspect annotation parsing to build Advisor)

Tips: The second and third above are implemented through your own defined advisors. There are no Spring annotations such as @Transactional. You can also use this or any other AOP annotation to observe the above three cases if you don’t mind.

So you can see from the above code that whether or not to use a proxy depends on whether Spring AOP is enabled and whether the corresponding class contains the logic that AOP needs to handle. Such as the custom @log annotation above or the related annotation in AspectJ.

3.2 How do I select the JDK agent and Cglib Agent

@enableAspectJAutoProxy (proxyTargetClass = true) enforces the Cglib proxy. But the default situation is how, we still according to look at the source code to analyze. To create a proxy class, use the AbstractAutoProxyCreator#createProxy method:

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 proxyFactory = new ProxyFactory();
	proxyFactory.copyFrom(this);
	// Set the Cglib proxy to be enforced
	if (proxyFactory.isProxyTargetClass()) {
		// Explicit handling of JDK proxy targets (for introduction advice scenarios)
		if (Proxy.isProxyClass(beanClass)) {
			// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
			for(Class<? > ifc : beanClass.getInterfaces()) { proxyFactory.addInterface(ifc); }}}else {
		// Determine whether to use the Cglib proxy without proxyTargetClass coercion, based on the proxy interface or proxy class
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
            // Evaluate the proxy interface
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	// Use original ClassLoader if bean class not locally loaded in overriding class loader
	ClassLoader classLoader = getProxyClassLoader();
	if (classLoader instanceofSmartClassLoader && classLoader ! = beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); }// Create the proxy class
	return proxyFactory.getProxy(classLoader);
}
Copy the code
  1. Use the proxyTargetClass tag to determine whether Cglib is forced to create the agent
  2. If proxyTargetClass=true is not set, the proxy mode is dynamically selected based on whether it is a proxy interface or a proxy class
  3. Create proxy class returns

4. To summarize

  • Proxy classes are not used and created without having to define them yourself when AOP is not enabled. That is, using different instances of the same class that we normally use
  • @enableAspectJAutoProxy (proxyTargetClass = true) forces all methods to use Cglib for proxying
  • By default, @enableAspectJAutoProxy determines whether to create a proxy class and whether to use a Jdk proxy implementation or a Cglib implementation