tiny-spring 源码分析 by Louis
tiny-spring是逐步进行构建的,里程碑版本我都使用了 git tag 来管理。例如,最开始的tag是step-1-container-register-and-get,那么可以使用下列命令获取各个版本
git checkout step-1-container-register-and-get
各版本见changelog.md
tiny-spring 是一个用于学习 Spring 的开源项目, 可以说是精简版的 Spring,其核心功能是:
- 支持 singleton 类型的 bean(可从 xml 读取),支持初始化、属性注入(包括依赖 bean 注入)。
- 可以使用
Aspectj的方式进行 AOP 编写,支持Java Proxy接口代理和 CGlib 的类代理。
代码目录树:
.
└── us
└── codecraft
└── tinyioc
├── BeanReference.java
├── aop
│ ├── AbstractAopProxy.java
│ ├── AdvisedSupport.java
│ ├── Advisor.java
│ ├── AopProxy.java
│ ├── AspectJAroundAdvice.java
│ ├── AspectJAwareAdvisorAutoProxyCreator.java
│ ├── AspectJExpressionPointcut.java
│ ├── AspectJExpressionPointcutAdvisor.java
│ ├── BeanFactoryAware.java
│ ├── Cglib2AopProxy.java
│ ├── ClassFilter.java
│ ├── JdkDynamicAopProxy.java
│ ├── MethodMatcher.java
│ ├── Pointcut.java
│ ├── PointcutAdvisor.java
│ ├── ProxyFactory.java
│ ├── ReflectiveMethodInvocation.java
│ └── TargetSource.java
├── beans
│ ├── AbstractBeanDefinitionReader.java
│ ├── BeanDefinition.java
│ ├── BeanDefinitionReader.java
│ ├── BeanPostProcessor.java
│ ├── PropertyValue.java
│ ├── PropertyValues.java
│ ├── factory
│ │ ├── AbstractBeanFactory.java
│ │ ├── AutowireCapableBeanFactory.java
│ │ └── BeanFactory.java
│ ├── io
│ │ ├── Resource.java
│ │ ├── ResourceLoader.java
│ │ └── UrlResource.java
│ └── xml
│ └── XmlBeanDefinitionReader.java
└── context
├── AbstractApplicationContext.java
├── ApplicationContext.java
└── ClassPathXmlApplicationContext.javaResource 接口标识一个“外部资源”,通过getInputStream() 获得输入流。
UrlResource 实现 Resource 接口,通过 URL 来 getInputStream()。
ResourceLoader 是一个资源加载类,用 getResource(String location) 返回一个 UrlResource。
public Resource getResource(String location){
// 资源加载
URL resource = this.getClass().getClassLoader().getResource(location);
return new UrlResource(resource);
}BeanDefinition 保存了所谓的bean的元数据,bean实际上就是任意的 Object。
元数据有 bean 对象本身(也就是 Object) ,bean 的类 beanClass,bean 的类名 beanClassName(用于反射),以及一个专门的 “属性对” 列表 propertyValues,里面放的是 PropertyValue:其实就是一个属性名和数值型。
public class BeanDefinition {
private Object bean;
private Class beanClass;
private String beanClassName;
private PropertyValues propertyValues = new PropertyValues();
public BeanDefinition() {
}
public void setBean(Object bean) {
this.bean = bean;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public String getBeanClassName() {
return beanClassName;
}
public void setBeanClassName(String beanClassName) {
this.beanClassName = beanClassName;
try {
this.beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public Object getBean() {
return bean;
}
public PropertyValues getPropertyValues() {
return propertyValues;
}
public void setPropertyValues(PropertyValues propertyValues) {
this.propertyValues = propertyValues;
}
}
public class PropertyValue {
private final String name;
private final Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Object getValue() {
return value;
}
}
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>();
public PropertyValues() {
}
public void addPropertyValue(PropertyValue pv) {
// TODO:这里可以对于重复propertyName进行判断,直接用 List 没法做到
this.propertyValueList.add(pv);
}
public List<PropertyValue> getPropertyValues() {
return this.propertyValueList;
}
}这里主要是用 XML 来读取 bean 的定义并加载到 registry 的字典里面,其他直接定义 bean 对象的情况不需要这个 BeanDefinitionReader。
BeanDefinitionReader 是一个通过 localtion 地址来加载 BeanDefinition 的接口
public interface BeanDefinitionReader {
void loadBeanDefinitions(String location) throws Exception;
}AbstractBeanDefinitionReader 实现上述接口的抽象类,实际上它并未具体实现了如何加载 BeanDefinition,而是规范了加载的流程:
- 我们还是需要用一个
ResourceLoader来获得Resource再得到输入流; - 我们要加载多个
BeanDefinition,用一个Map<String, BeanDifinition>的 registry 来保存读入的结果。
具体实现如何从 XML 中解析生成 Bean 并保存到 registry
@Override
public void loadBeanDefinitions(String location) throws Exception {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinitions(inputStream);
}XML 中 bean 的定义如下,bean 要注明 id 即 bean 的 nane,以及对应的类
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="outputService" class="us.codecraft.tinyioc.OutputServiceImpl">
</bean>
<bean id="helloWorldService" class="us.codecraft.tinyioc.HelloWorldServiceImpl">
<property name="text" value="Hello World!"></property>
<property name="outputService" ref="outputService"></property>
</bean>
<bean id="autoProxyCreator" class="us.codecraft.tinyioc.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>
<bean id="timeInterceptor" class="us.codecraft.tinyioc.aop.TimerInterceptor"></bean>
<bean id="aspectjAspect" class="us.codecraft.tinyioc.aop.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="timeInterceptor"></property>
<property name="expression" value="execution(* us.codecraft.tinyioc.*.*(..))"></property>
</bean>
</beans>每读入一个 bean 条目,创建一个 BeanDefinition:
protected void processBeanDefinition(Element ele) {
String name = ele.getAttribute("id");
String className = ele.getAttribute("class");
// 创建新的 BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
// 处理属性
processProperty(ele, beanDefinition);
beanDefinition.setBeanClassName(className);
// 注册到 registry
getRegistry().put(name, beanDefinition);
}在处理 bean 属性的时候,如果出现了 ref,即要注入其他的 bean,这里特别定义了一个 BeanReference 类保存被引用的 bean,这里创建一个保存 bean 名称的 BeanReference,最后 getBean() 会从这个类里调。
public class BeanReference {
private String name;
private Object bean;
public BeanReference(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
}
// XmlBeanDefinitionReader 处理 ref 属性
String ref = propertyEle.getAttribute("ref");
if (ref == null || ref.length() == 0) {
throw new IllegalArgumentException("...");
}
BeanReference beanReference = new BeanReference(ref); // 用 ref 的 bean name 创建 BeanReference
beanDefinition.getPropertyValues().addPropertyValue(new PropertyValue(name, beanReference));BeanFactory 是通过 bean 的 name 调用 getBean(String name) 返回 bean 对象的一个接口。
AbstractBeanFactory 没有具体实现怎么生成 bean Object,只是规范了工厂生成 Bean、初始化、实例化、注入属性等一系列流程。
首先,AbstractBeanFactory 有一个 beanDefinitionMap,用来保存将要生成的 bean 类的定义信息:
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();工厂的 getBean() 方法实现了单例模式:如果从类定义信息 beanDefination 中 getBean()得到的 bean 实例不存在,那么要新创建一个 bean,如果存在则直接返回。
@Override
public Object getBean(String name) throws Exception {
BeanDefinition beanDefinition = beanDefinitionMap.get(name);
if (beanDefinition == null) {
throw new IllegalArgumentException("No bean named " + name + " is defined");
}
Object bean = beanDefinition.getBean();
if (bean == null) {
bean = doCreateBean(beanDefinition); // 1. 创建 bean 实例
bean = initializeBean(bean, name); // 2. 初始化 bean 实例
beanDefinition.setBean(bean); // 3. bean 实例放回 beanDefinition 中
}
return bean;
}虽然 doCreateBean 已经在 beanDefinition 中设置了 bean,但是后面初始化 bean 的时候,对 bean 又进行了改动,所以上面(第3步)还要 setBean 一次。
创建 bean 实例的过程由 doCreateBean(BeanDefinition beanDefinition)完成:
其又分为创建实例、定义中写入实例
protected Object doCreateBean(BeanDefinition beanDefinition) throws Exception {
Object bean = createBeanInstance(beanDefinition);
beanDefinition.setBean(bean);
applyPropertyValues(bean, beanDefinition);
return bean;
}doCreateBean 也分为 3 步:
- 用
createBeanInstance实例化 bean,是通过beanDefinition中的beanClass的newInstance()方法 - 还是要为
beanDefinition更新 bean 实例:setBean(bean) - 调用
applyPropertyValues方法 将beanDefinition中的属性对应用到 bean 实例中(这一步由子类实现)
这个第 3 步是如何注入属性,在此处也是这个 AbstractBeanFactory 未完成的功能,项目中由子类AutowireCapableBeanFactory实现。
类中还存在其他 AOP 相关的内容,后面再讲。
这里注入属性只有一种方法,也就是自动装配内容,从 BeanDefinition 的 propertyValueList 读取属性名和属性值的键值对 PropertyValue,用反射的方法注入。这里优先使用属性对应的set方法注入属性,没有此方法才直接对属性赋值(因为通常是私有域,按理是不能去访问的)。
还有一种情况是属性是其他 bean 对象,那么获得的值是保存了bean name 的 BeanReference,还要用本 Factory 的 getBean() 方法找到这个 bean 再作为属性值。
public class AutowireCapableBeanFactory extends AbstractBeanFactory {
protected void applyPropertyValues(Object bean, BeanDefinition mbd) throws Exception {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
for (PropertyValue propertyValue : mbd.getPropertyValues().getPropertyValues()) {
Object value = propertyValue.getValue();
if (value instanceof BeanReference) {
BeanReference beanReference = (BeanReference) value;
value = getBean(beanReference.getName());
}
try {
Method declaredMethod = bean.getClass().getDeclaredMethod(
"set" + propertyValue.getName().substring(0, 1).toUpperCase()
+ propertyValue.getName().substring(1), value.getClass());
declaredMethod.setAccessible(true);
declaredMethod.invoke(bean, value);
} catch (NoSuchMethodException e) {
Field declaredField = bean.getClass().getDeclaredField(propertyValue.getName());
declaredField.setAccessible(true);
declaredField.set(bean, value);
}
}
}
}ApplicationContext 只是简单继承了 BeanFactory,什么都没做,是一个标记接口。
注意上面的 BeanFactory 只是直接通过 BeanDefinition 实现了 bean 的装载、获取,bean 的来源(BeanDefinition是 怎么来的)没有指定。现在我们顺便结合 BeanDefinitionReader 获取 BeanDefinition 的 registry,再对 bean 进行实例化。
是上面 ApplicationContext 接口的抽象实现类,内部包含了一个 BeanFactory,内部主要方法有 refresh() 和 getBean() 。
public void refresh() throws Exception {
loadBeanDefinitions(beanFactory);
registerBeanPostProcessors(beanFactory); // 注册 bean 后处理器
onRefresh();
}refresh()方法先调用 loadBeanDefinitions来读取 BeanDefinition,然后onRefresh() 间接调用 beanFactory 对 bean 预实例化。
所谓预实例化 preInstantiateSingletons 就是对所有 bean 调用 getBean() 方法,就生成实例了。
getBean() 是直接调用工厂 beanFactory 的 getBean() 获取实例。
毫无疑问 ClassPathXmlApplicationContext 要做的就是如何 loadBeanDefinitions,回到我们的
XmlBeanDefinitionReader,它需要一个ResourceLoader,然后调用 ResourceLoader 的 loadBeanDefinitions来获取 bean 的定义:BeanDefinition。由于 XmlBeanDefinitionReader 是把BeanDefinition放在其 registry 字典中的,我们要调用 beanFactory.registerBeanDefinition 将它注册到 beanFactory。
除了 BeanFactory之外,还要给 ClassPathXmlApplicationContext 指定一个 location,即 XML 文件的路径。
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
private String configLocation;
public ClassPathXmlApplicationContext(String configLocation) throws Exception {
this(configLocation, new AutowireCapableBeanFactory());
}
public ClassPathXmlApplicationContext(String configLocation, AbstractBeanFactory beanFactory) throws Exception {
super(beanFactory);
this.configLocation = configLocation;
refresh();
}
@Override
protected void loadBeanDefinitions(AbstractBeanFactory beanFactory) throws Exception {
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(new ResourceLoader());
xmlBeanDefinitionReader.loadBeanDefinitions(configLocation);
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : xmlBeanDefinitionReader.getRegistry().entrySet()) {
beanFactory.registerBeanDefinition(beanDefinitionEntry.getKey(), beanDefinitionEntry.getValue());
}
}
}注 1:在 Spring 的实现中,对
ApplicatinoContext的分层更为细致。AbstractApplicationContext中为了实现 不同来源 的 不同类型 的资源加载类定义,把这两步分层实现。以“从类路径读取 XML 定义”为例,首先使用AbstractXmlApplicationContext来实现 不同类型 的资源解析,接着,通过ClassPathXmlApplicationContext来实现 不同来源 的资源解析。
注 2:在 tiny-spring 的实现中,先用
BeanDefinitionReader读取BeanDefiniton后,保存在内置的registry(键值对为String-BeanDefinition的哈希表,通过getRigistry()获取)中,然后由ApplicationContext把BeanDefinitionReader中registry的键值对一个个赋值给BeanFactory中保存的beanDefinitionMap。而在 Spring 的实现中,BeanDefinitionReader直接操作BeanDefinition,它的getRegistry()获取的不是内置的registry,而是BeanFactory的实例。如何实现呢?以DefaultListableBeanFactory为例,它实现了一个BeanDefinitonRigistry接口,该接口把BeanDefinition的 注册 、获取 等方法都暴露了出来,这样,BeanDefinitionReader可以直接通过这些方法把BeanDefiniton直接加载到BeanFactory中去。
下面说说 AOP 实现部分
JDK 的动态代理主要有两个关键类:Proxy 和 InvocationHandler,都在 java.lang.reflect 中。
Proxy 可以通过: Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个代理对象。
InvocationHandler 可以通过Object invoke(Object proxy, Method method,Object[] args) 来处理代理对象具体的方法调用。
public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {
public JdkDynamicAopProxy(AdvisedSupport advised) {
super(advised);
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(getClass().getClassLoader(), advised.getTargetSource().getInterfaces(), this);
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
if (advised.getMethodMatcher() != null
&& advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(),
method, args));
} else {
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
}当然这里先得有个 AopProxy 接口,可以 getProxy(),然后 AbstractAopProxy 实现 AopProxy 并且设置了名为 advised 的AdvisedSupport属性,
AdvisedSupport 是存放拦截的内容 TargetSource 、拦截器 MethodInterceptor 以及拦截匹配 MethodMatcher的类,因为这三个东西是同时处理的。
上面的 invoke(Object proxy, Method method, Object[] args) 的拦截逻辑是 advised 中的 MethodMatcher 如果能够 match 我们的目标类、方法和参数,那么就调用 advised 中的 MethodInterceptor 来 invoke 操作,否则是用原生的 method.invoke(object, args),即不拦截,调用原对象的方法。
再介绍下 MethodInterceptor,这是 org.aopalliance.inercept 中的对象
MethodInterceptor 对象调用 invoke 要传入一个实现MethodInvocation接口的对象(有个getMethod()方法),注释中写道:method invocation 就是能被方法拦截器拦截的连接点,最重要的其实是 JoinPoint 中的 proceed() 方法。
看 MethodInterceptor 是如何 invoke 调用 MethodInvocation 的:
public class TimerInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 方法前操作
long time = System.nanoTime();
System.out.println("Invocation of Method " + invocation.getMethod().getName() + " start!");
// invocation 继续执行原先的代码
Object proceed = invocation.proceed();
// 方法后操作
System.out.println("Invocation of Method " + invocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time)
+ " nanoseconds.");
return proceed;
}
}看 JdkDynamicAopProxyTest:
public class JdkDynamicAopProxyTest {
@Test
public void testInterceptor() throws Exception {
// --------- helloWorldService without AOP
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("tinyioc.xml");
HelloWorldService helloWorldService = (HelloWorldService) applicationContext.getBean("helloWorldService");
helloWorldService.helloWorld();
// --------- helloWorldService with AOP
// 1. 设置被代理对象(Joinpoint)
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(helloWorldService, HelloWorldServiceImpl.class,
HelloWorldService.class);
advisedSupport.setTargetSource(targetSource);
// 2. 设置拦截器(Advice)
TimerInterceptor timerInterceptor = new TimerInterceptor();
advisedSupport.setMethodInterceptor(timerInterceptor);
// 3. 这里我们忽略 advisedSupport 中的 MethodMatcher,因为它是后面 AspectJ 才用到的,这里只做测试
// 3. 创建代理(Proxy)
JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();
// 4. 基于AOP的调用
helloWorldServiceProxy.helloWorld();
}
}工厂方法中的 getBean()的两个步骤:
doCreateBean创建 bean 实例,注入属性initializeBean初始化 bean 实例
第一步在创建实例的时候,有个 applyProperties,具体操作在唯一的具体 Factory 类 AutowireCapableBeanFactory 的 applyPropertyValues 方法(为了给 bean 注入属性)中,我们有这么一段:
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}也就是如果 bean 实现了 BeanFactoryAware 接口,就转换成 BeanFactoryAware 调用 setBeanFactory,将工厂容器的引用传回 bean 中,这样 bean 就可以获得对容器操作的权限,允许了编写扩展 IoC 容器功能的 bean。
注:上面没有说明,
AbstractBeanFactory里面除了 beanDefinationMap 之外,还有 beanDefinationNames 的 List 存放每个 BeanDefiniton 的名称,更重要的是还有一个beanPostProcessors的列表(存放实现BeanPostProcessor接口的对象)
对于第二步在代码中其实没有写初始化 bean 的逻辑,这里初始化逻辑之前和之后,从 beanPostProcessor 列表中获得每个后处理器,对 bean 进行处理。
protected Object initializeBean(Object bean, String name) throws Exception {
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessBeforeInitialization(bean, name);
}
// TODO:call initialize method
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
bean = beanPostProcessor.postProcessAfterInitialization(bean, name);
}
return bean;
}当然,经过 BeanPostProcessor 处理之后的 bean 可以是动态代理返回的代理类,比如我们在postProcessAfterInitialization(bean, name)中去调用 JdkDynamicAopProxy对象的 getProxy来返回一个新的 代理bean,这样就在初始化 bean 的过程中,动态代理了 bean 对象。
由于 ApplicationContext 有个 refresh 方法,里面有 registerBeanPostProcessors 方法,其实就是加到 BeanFactory 的 beanPostProcessors 列表里面。
XML 的 bean 定义中,加上这个 BeanPostProcessor 的 bean 就可以了
<bean id="beanInitializeLogger" class="us.codecraft.tinyioc.BeanInitializeLogger">// 当然这里并没有创建代理对象,还是返回原理的bean
public class BeanInitializeLogger implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
System.out.println("Initialize bean " + beanName + " start!");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
System.out.println("Initialize bean " + beanName + " end!");
return bean;
}
}在初始化 bean 时调用后处理器,这里是默认所有 bean 都会被所有 BeanPostProcessor 处理。
先介绍一下Pointcut接口,即切点,提供用于类过滤的 ClassFilter、方法匹配的MethodMatcher。
这三者是紧密相关的。
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher()
}
public interface ClassFilter {
boolean matches(Class targetClass);
}
public interface MethodMatcher {
boolean matches(Method method, Class targetClass);
}接下来PointcutAdvisor是切点通知器,可以getPointcut()得到一个切点,又因为继承自 Advisor可以得到一个 Advice增强:Advice就是一个通知对象,用于实现具体的方法拦截。
public interface PointcutAdvisor extends Advisor{
Pointcut getPointcut();
}之前这部分内容我们是在 AdvisedSupport 中保存。
我们看具体的 AspectJExpressionPointcut,它既是一个 Pointcut,又自己实现了 ClassFilter和MethodMatcher,所以它的 getPointcut()就返回自己了,另外还可以 match 类和方法。
这个Pointcut需要传入一个 expression 匹配表达式,用 PointcutParser结合这个 expression 来构造 PointcutExpression,接下来就可以用``PointcutExpression` 来 match 匹配类和方法了。
@Override
public boolean matches(Class targetClass) {
checkReadyToMatch();
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matches(Method method, Class targetClass) {
checkReadyToMatch();
ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
if (shadowMatch.alwaysMatches()) {
return true;
} else if (shadowMatch.neverMatches()) {
return false;
}
// TODO:其他情况不判断了!见org.springframework.aop.aspectj.RuntimeTestWalker
return false;
}实现 PointcutAdvisor 接口。
上面 AspectJExpressionPointcut 是一个传入 expression 然后 match 的功能,我们新的 Advisor 组合了 Pointcut 和 Advice。
public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
private AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
private Advice advice;
public void setAdvice(Advice advice) {
this.advice = advice;
}
public void setExpression(String expression) {
this.pointcut.setExpression(expression);
}
@Override
public Advice getAdvice() {
return advice;
}
@Override
public Pointcut getPointcut() {
return pointcut;
}
}AspectJAwareAdvisorAutoProxyCreator 类(以下简称 AutoProxyCreator)是实现 AOP 植入的关键类,它实现了两个接口:
BeanPostProcessor:在postProcessorAfterInitialization方法中,使用动态代理的方式,返回一个对象的代理对象。解决了 在 IoC 容器的何处植入 AOP 的问题。BeanFactoryAware:这个接口提供了对BeanFactory的感知,这样,尽管它是容器中的一个Bean,却可以获取容器的引用,进而获取容器中所有的切点对象,决定对哪些对象的哪些方法进行代理。解决了 为哪些对象提供 AOP 的植入 的问题。
public class AspectJAwareAdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware {
// AspectJAwareAdvisorAutoProxyCreator 是一个 bean,但是实现了 BeanFactoryAware,可以保存工厂
private AbstractBeanFactory beanFactory;
// 初始化前什么都不作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
// 初始化后
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
// 注意,这里的 bean 是doCreation中 initializeBean 初始化的时候传进来的
// 是否要进行拦截处理
// 一些 Adivisor 增强类,不需要增强自身,排除
if (bean instanceof AspectJExpressionPointcutAdvisor) {
return bean;
}
// 一些方法拦截器,排除
if (bean instanceof MethodInterceptor) {
return bean;
}
// 通过 bean factory 找到所有 AspectJExpression 的 PointcutAdvisor(保存了pointcut和advisor)
List<AspectJExpressionPointcutAdvisor> advisors = beanFactory
.getBeansForType(AspectJExpressionPointcutAdvisor.class);
// 遍历所有的 pointcut & advisor
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
// 类匹配与否
if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) {
// 还是用之前的 AdvisedSupport 来保存拦截类、方法匹配、拦截器
AdvisedSupport advisedSupport = new AdvisedSupport();
// 拦截器从 advisor.getAdvice() 得到:MethodInterceptor 继承自 Advice
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
TargetSource targetSource = new TargetSource(bean, bean.getClass().getInterfaces());
advisedSupport.setTargetSource(targetSource);
// 返回新的 JDK 动态代理
return new JdkDynamicAopProxy(advisedSupport).getProxy();
}
}
// 匹配不了就直接返回
return bean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws Exception {
this.beanFactory = (AbstractBeanFactory) beanFactory;
}
}XML 注入:
<bean id="autoProxyCreator" class="us.codecraft.tinyioc.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>
<bean id="aspectjAspect" class="us.codecraft.tinyioc.aop.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="timeInterceptor"></property>
<property name="expression" value="execution(* us.codecraft.tinyioc.*.*(..))"></property>
</bean>总而言之:AspectJAwareAdvisorAutoProxyCreator只要注入后,会自动在实例初始化阶段收集所有的 AspectJExpressionPointcutAdvisor(属性如上只需要提供 advice ref是什么,以及 expression 就好了),实现 AspectJ 的动态代理。
Java 的 JDK 动态代理只能代理接口,即我们的代理对象 Target Class 只能是接口,而不能是 Impl 实现类。
CGLib 可以实现对类的代理,是对 ASM 的封装,Spring 中使用了 CGLib。
可以定义一个工厂类ProxyFactory,用于根据 TargetSource 类型自动创建代理,这样就需要在调用者代码中去进行判断。
// AopProxy 可以是 JdkDynamicAopProxy 或者 Cglib2AopProxy
public class ProxyFactory extends AdvisedSupport implements AopProxy {
@Override
public Object getProxy() {
return createJdkDynamicAopProxy
// return createAopProxy().getProxy();
}
protected final AopProxy createCglibAopProxy() {
return new Cglib2AopProxy(this);
}
protected final AopProxy createJdkDynamicAopProxy() {
return new JdkDynamicAopProxy(this);
}
}import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Cglib2AopProxy extends AbstractAopProxy {
public Cglib2AopProxy(AdvisedSupport advised) {
super(advised);
}
// 返回一个 proxy : enhanced
@Override
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTargetClass());
enhancer.setInterfaces(advised.getTargetSource().getInterfaces());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised)); // 设置回调的 MethodInterceptor(主要是 里面的 intercept 函数返回的 MethodInvocation 对象)
Object enhanced = enhancer.create();
return enhanced;
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advised;
private org.aopalliance.intercept.MethodInterceptor delegateMethodInterceptor;
private DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
this.delegateMethodInterceptor = advised.getMethodInterceptor();
}
// 什么情况下拦截
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (advised.getMethodMatcher() == null
|| advised.getMethodMatcher().matches(method, advised.getTargetSource().getTargetClass())) {
return delegateMethodInterceptor.invoke(new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy));
}
return new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, args, proxy).proceed();
}
}
// MethodInvocation 如何拦截,主要是 preceed()
// 主要这个 proceed 方法,内部是用 这个 getProxy() 返回的Enhancer代理来 invoke
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] args, MethodProxy methodProxy) {
super(target, method, args);
this.methodProxy = methodProxy;
}
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.target, this.arguments);
}
}
}




