Spring AOP source directory
Spring AOP Source 01: Jdk dynamic proxy for the underlying source
Spring AOP Source 02: the ProxyFactory
Spring AOP Source 03: JdkDynamicAopProxy
Spring AOP Source 04: MethodInvocation call interceptor
Spring AOP Source 05: The DefaultAdvisorAutoProxyCreator
the Spring finale final exam question: When Spring AOP met circular dependencies
Notes git source address: https: //github.com/chaitou/spring-framework-master.git
Foreword
This article deals focus on analysis of ProxyFactory
the class source code, many people do not understand why you want to explain most of the energy is spent ProxyFactory
on, after all, no one would use such a low-level Spring AOP implementations?
ProxyFactory need to manually set the proxy to achieve Traget
(the target object), Interface
(interface), Advice
(enhanced), then call getProxy
generates a proxy object. The use of annotations in the form of Spring AOP did not imagine the complex, but is looking for all @Aspect
annotated classes and all @Before
and other enhancements, and then through the @Pointcut
matching conditions on the match, and finally get to all matching the Advice
(enhanced) were generated proxy. Therefore, the comment form AOP not esoteric, just to help us automatically 寻找匹配增强
and create Bean in Spring Ioc the process of looking for 合适的时机
, call getProxy generating agent, nothing more. So, if we manually hard-coded ( ProxyFactory
) and thoroughly, and basically also mastered Spring AOP, as to the form of notes, we just have to explore about Advice
how to obtain and match it
Notes cutaway Xml configuration, the core Spring AOP is to ProxyFactory
seize the main line, in order to better grasp the context of the source code, and will not be disturbed by the details of the corner
ProxyFactory
The sample code
We will write an UserService
interface that defines findUser
methods while before with after using the Advice
method of enhanced (enhanced), last used ProxyFactory
were generated proxy.
Here it is necessary to broadly introduce Advice (enhanced) and Advisor (section), two words a bit like a long, but they are the aggregation relationship.
- Enhanced (
Advice
): a commonBefore advice
,After returning advice
that is to expand operations at the connection point - Cut Point (
Pointcut
): i.e. connection point, for determining whether the current method or class enhanced - Section (
Advisor
): can be seen in增强
and切点
binding. Suppose a method needs to be enhanced, then cut through all the callsPointcut
to judge whether the current section applies, if applicable, is called the currentAdvice
enhanced
interface:
public interface UserService {
public void findUser();
}
Implementing Classes:
public class UserServiceImpl implements UserService {
@Override
public void findUser() {
System.out.println("findUser...");
}
}
2 enhancements:
// 前置增强
public class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before log...");
}
}
// 后置增强
public class LogAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("after log...");
}
}
test:
public class UserServiceImplImplTest {
@Test
public void findUser() {
// 1. 创建代理工厂
ProxyFactory factory = new ProxyFactory();
// 2. 设置代理目标对象
factory.setTarget(new UserServiceImpl());
// 3. 设置接口
factory.setInterfaces(new Class[]{UserService.class});
// 4. 设置增强
factory.addAdvice(new LogBeforeAdvice());
factory.addAdvice(new LogAfterAdvice());
// 5. 获取代理对象
UserService userService = (UserService) factory.getProxy();
userService.findUser();
}
}
operation result:
before log...
findUser...
after log...
Process finished with exit code 0
ProxyFactory inheritance
We care about the focus of the class, ignoring Interface
ProxyConfig
: Proxy configuration for saving related infrastructure, such as whether to use aggressive mode, optimize, forcibly opened cglib agent proxyTargetClass, if exposed to the agent exposeProxy etc., is very common in the xml configuration, such as<aop:aspectj-autoproxy proxy-target-class="true"/>
forced on Cglib agentAdvisedSupport
: AOP configuration management class, compared ProxyConfig, which also holdstargetSource
a collection of cutadvisors
, set of interfacesinterfaces
, etc.ProxyCreatorSupport
: Agent base class facilities, which provide for a configurableAopProxyFactory
and easy access
Source code analysis
- Create a proxy factory, calling the default constructor direct air
- Set up a proxy target object, the
target
object is encapsulated intoTargetSource
an object, why should we bother? In fact,TargetSource
the purpose is to make use object pooling and more cases, that each agent will get the object from the pool. And here we use onlySingletonTargetSource
, onTargetSource
leave back to explain. Just mentioned these attributes are stored inAdvisedSupport
the
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
@Override
public void setTargetSource(@Nullable TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
- Setting an array of interfaces, also stored to
AdvisedSupport
the properties
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
// 先清空再添加
this.interfaces.clear();
for (Class<?> ifc : interfaces) {
addInterface(ifc);
}
}
public void addInterface(Class<?> intf) {
Assert.notNull(intf, "Interface must not be null");
// 校验如果不是接口则抛出异常
if (!intf.isInterface()) {
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
}
if (!this.interfaces.contains(intf)) {
this.interfaces.add(intf);
adviceChanged();
}
}
- Set
Advice
, as we saidAdvice
just increased, so we have to package into aAdvisor
section added toAdvisedSupport
theadvisors
collection. And because there is no need to pay attention to the configuration of anyPointcut
, so we will useDefaultPointcutAdvisor
created
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
// 单独处理引介增强
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
// DynamicIntroductionAdvice只能作为IntroductionAdvisor的一部分
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
// 普通增强
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}
And DefaultPointcutAdvisor
means that no matter what methods are matched, so you can see Pointcut using Pointcut.TRUE
whatever method matches are true
new DefaultPointcutAdvisor(advice)
// Pointcut.TRUE
// 也就是说该Advisor的匹配均为true,匹配任何的方法,不做任何限制!
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
- Create an agent, this is the highlight of Benpian
public Object getProxy() {
return createAopProxy().getProxy();
}
Code createAopProxy().getProxy()
one, calling getProxy()
before, we have to figure out what the object is called getProxy()
, in other words, createAopProxy()
in the end what the object is created
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
----------------------------------------------------------------
public AopProxyFactory getAopProxyFactory() {
// 返回的是类中的成员变量aopProxyFactory
return this.aopProxyFactory;
}
----------------------------------------------------------------
// 成员变量的实例化则是在默认构造器中
private AopProxyFactory aopProxyFactory;
// 构造器,调用了DefaultAopProxyFactory进行实例化,因此aopProxyFactory真正的类型是DefaultAopProxyFactory
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
Tracking found createAopProxy()
returns attribute aopProxyFactory
, the attribute aopProxyFactory
is on ProxyCreatorSupport
for constructing an instantiated class is real DefaultAopProxyFactory
, and therefore continue to follow DefaultAopProxyFactory
the createAopProxy
method of
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// isOptimize开启激进模式 || proxyTargetClass=true(强制开启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);
}
// 没有接口,只能选择cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用JDK代理
return new JdkDynamicAopProxy(config);
}
}
...
}
It can be seen as config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)
is true only use Cglib agent, and when there is a proxy object implements the interface, and not forced on the default proxy is used when cglib JDK proxy, that is JdkDynamicAopProxy
class.
In other words, the final call is actually a new JdkDynamicAopProxy(config).getProxy()
combination Jdk dynamic proxy for the underlying source content, it is expected to have two methods require special attention. getProxy
And invoke
methods
// JdkDynamicAopProxy.java
@Override
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);
// 判断接口是否又hashCode和equals方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK代理(classLoader, 接口, 当前JdkDynamicAopProxy对象:用于回调invoke和target对象方法)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
// 上述代码
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
// 第一篇[Jdk动态代理底层源码]中学习的代码是一模一样的
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
As can be seen, in fact, each knowledge point are associated together, ProxyFactory
as the core of Spring AOP, we also studied the use of Jdk动态代理
to achieve. Combining the first chapter Jdk dynamic proxy for the underlying source content, it is the most important getProxy
and invoke
method, the next section we will be JdkDynamicAopProxy
in getProxy
and invoke
source code analysis methods