一、Spring IOC体系学习总结:

Spring中有两个容器体系,一类是BeanFactory、还有一类是ApplicationContext。BeanFactory提供了基础的容器功能。ApplicationContext则是基于BeanFactory建立的一套更加丰富的容器体系,基于ApplicationContext构建了Spring AOP体系(基于AOP体系又构建了声明式事务模型),I18n的支持,基于观察者模式的事件模型,多渠道的Bean资源的加载(比方从文件系统,从internet)。以下看一下两个容器体系的类结构图。

BeanFactory容器体系结构图:



如上图:BeanFactory接口定义了IOC容器的最主要的方法,比如getBean,isSingleton等。子类ListableBeanFactory则是补充定义了批量获取Bean信息的一些列表方法,好多方法返回的都是数据或者列表,比方获取全部的Bean的名字等。

而子类HierarchialBeanFactory则是描写叙述了IOC容器的双亲模型,是IOC容器具备了管理双亲容器的功能。比如加入了getParentBeanFactory的功能(这里展开一下,在获取Bean的时候。是先在父容器中去获取,假设获取不到,才会在本身的容器中获取)。

最后ConfigurableBeanFactory定义了IOC容器的一些配置功能。比如加入了setParentBeanFactory方法。addBeanPostProcessor配置Bean后置处理器的方法等。通过观察继承体系能够看出。DefaultListableBeanFactory辗转反側的继承了全部的接口,由此可见DefaultListableBeanFactory是比較土豪的,是在BeanFactory容器体系下比較完好的容器模型。

(1) 看下直接通过编程式使用 BeanFactory的一个样例,顺便分析一下:

ClassPathResource res = new ClassPathResource("beans.xml");
//直接使用DefaultListableBeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);

上述代码相应了BeanFactory载入beans.xml的过程。详细相应到Spring的载入过程为:

调用DefaultListBeanFactory的registerBeanDefinition方法的代码为:

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

能够看到传入的參数有两个 一个是bdHolder这个相应的事实上就是BeanDefinition的包装。另外一个就是BeanDefinitionRegistry对象。

而这个BeanDefinitionRegistry对象的实例就是DefaultListBeanFactory。參考例如以下继承关系:



所以事实上调用就是 DefaultListBeanFactory 的 registerBeanDefinition 方法:

/**
* 向BeanFactory的map容器中注冊Bean
*/
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
} synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//当不同意新的Bean覆盖老的Bean时,则会抛异常出来
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName);
}
}

支持BeanDefinition的信息都被注冊到了DefaultListBeanFactory中。

(2) 以上看到了BeanDefinition注冊到DefaultListBeanFactory的过程,当中BeanDefinition事实上就相应了我们xml文件里配置的Bean的信息,BeanDefinition信息注冊到DefaultListBeanFactory中事实上并没有完毕对Bean的实例化,注冊的仅仅是Bean实例的元数据信息。即还没有完毕Bean依赖的关系的注入。首先看下BeanDefinition的类的继承体系:

这个图就看看得了,不具体分析了。

以下再看下Xml配置文件中的Bean是怎样变成BeanDefinition的:

BeanDefinitionParserDelegate封装了解析Xml文件的一些方法,主要有这个Delegate将Xml文件解析成BeanDefinition。

(3) 上面看到了BeanDefinition的解析以及注冊到BeanFactory的过程。

然后就是针对BeanDefinition的完毕Bean依赖关系的注入过程。

获取一个Bean的实例并完毕注入的步骤例如以下:

当中 AbstractAutowireCapableBeanFactory 的 populateBean 是实际发生Bean依赖注入的地方。

详细的代码例如以下:

//实际涉及到bean注入的方法
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
} // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
} if (!continueWithPropertyPopulation) {
return;
} if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
} // Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
} pvs = newPvs;
} boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
//检查Bean的依赖是否已经装配好
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//对属性进行依赖注入
applyPropertyValues(beanName, mbd, bw, pvs);
}

(4) Spring的还有一种高级的容器ApplicationContext在BeanFactory的基础上加入了很多其它的面向框架的功能,比方和AOP的融合,生命周期的管理。Bean处理器(BeanProcessor)加入等,上面已经说了。就不提了。下文看下ApplicationContext的类继承关系图:

简述:ApplicationContext 的子类主要包括两个方面:ConfigurableApplicationContext 表示该 Context 是可改动的,也就是在构建 Context 中用户能够动态加入或改动已有的配置信息,它以下又有多个子类,当中最常常使用的是可更新的 Context,即:AbstractRefreshableApplicationContext 类。 WebApplicationContext 顾名思义。就是为 web 准备的 Context 他能够直接訪问到 ServletContext。通常情况下。这个接口使用的少。
再往下分就是依照构建 Context 的文件类型,接着就是訪问 Context 的方式。

这样一级一级构成了完整的 Context 等级层次。

整体来说 ApplicationContext 必需要完毕下面几件事:

I.标识一个应用环境

II.利用 BeanFactory 创建 Bean 对象

III.保存对象关系表

IV.可以捕获各种事件

V.Context 作为 Spring 的 Ioc 容器。基本上整合了 Spring 的大部分功能,或者说是大部分功能的基础。

ApplicationContext和BeanFactory及ResourceLoader的关系例如以下图:



ApplicationContext继承了ResourceLoader。注定了ApplicationContext能够完毕多渠道外部资源的读入,不光是能够载入配置的xml文件。还有上图也清晰的标识了ApplicationContext和BeanFactory的关系。

ApplicationContext容器初始化的过程还是能够看上面那个时序图:

AbstractApplicationContext的容器初始化过程是通过调用Refresh方法完毕的,详细方法的代码例如以下:

//整个容器启动的入口
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
// 在子类中启动RefreshBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
//设置post的后置处理
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
//调用Bean的后置处理器,后置处理器是在Bean定义时向容器注冊的
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
//注冊Bean的后置处理器,在Bean创建过程中调用
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
//对上下文的消息源进行初始化
initMessageSource(); // Initialize event multicaster for this context.
//初始化上下文的事件机制
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
//初始化其它的特殊Bean
onRefresh(); // Check for listener beans and register them.
//检查监听Bean并将这些Bean向容器注冊
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
//实例化全部的(non-lazy-init)单件
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
//公布容器事件,结束Refresh进程
finishRefresh();
} catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
}
}

上面的代码中。每一步干什么都写了凝视。

以下再补充扩展一下ResourceLoader和Resource的类体系结构图:

ResourceLoader的类体系结构图:

Resource的类体系结构图:

Resource抽象出了资源的概念。这里的资源就能够理解为Spring容器须要载入的Bean的元数据。ApplicationContext继承了ResourceLoader。使其具备了载入元数据资源的能力。

最后再附上一张BeanFactory和ApplicationContext比較完毕的类体系结构图:

(5) IOC容器大体的结构就说这么多。以下总结一下几个常见的问题:

Spring中的FactoryBean怎么理解:

Spring中有两种类型的Bean:一种是普通的javaBean。还有一种就是工厂Bean(FactoryBean),这两种Bean对IOC容器BeanFactory来说在获取Bean的方式上有一些细微的区别。看个实例DEMO:

public class MyFactoryBean implements FactoryBean<Date>,BeanNameAware {

private String name;

@Override
public void setBeanName(String name) {
this.name = name;
} @Override
public Date getObject() throws Exception {
return new Date();
} @Override
public Class<? > getObjectType() {
return Date.class;
} @Override
public boolean isSingleton() {
return false;
} public void sayName() {
System.out.println("My name is "+this.name);
} public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource("/aop/demo/demo4/applicationContext.xml");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(resource);
//这里获取的事实上是自己定义FactoryBean中getObject获取到的Value
Date now = (Date) beanFactory.getBean("myFactoryBean");
System.out.println(now);
//这里获取的是FactoryBean
MyFactoryBean factoryBean = (MyFactoryBean) beanFactory.getBean("&myFactoryBean");
factoryBean.sayName();
}
}

运行的输出结果:

Thu May 08 09:46:43 CST 2014
My name is myFactoryBean

看代码,从BeanFactory中获取 myFactoryBean的过程中依据两种名字进行获取 分别为 myFactoryBean,&myFactoryBean,通过myFactoryBean获取到的Bean假设实现了Spring定义的FactoryBean的接口。那么将会调用该接口的getObject方法,获取真是的值。假设&myFactoryBean来获取Bean的话就直接返回 FactoryBean实例。FactoryBean这个类型的Bean事实上是Spring为我们提供的一个扩展点。我们能够自行定义FactoryBean。然后对容器中真实的对象做一些包装处理,比如为了实现Spring
AOP,则定义了 ProxyFactoryBean,在调用器getObject方法时。对目标对象进行了动态代理。将横切逻辑编织到目标对象的方法逻辑中,详细分析下文有讲述。

BeanFactory 和 ApplicationContext 在获取Bean方式上的差别?

BeanFactory在获取Bean的时候,是延迟加载的,既不会完毕BeanDefinition的加载。也不会完毕Bean的依赖注入,xml文件即使配置错了也不会检查出来,它是在获取的时候才完毕了Bean的关联关系的注入的。而ApplicationContext则是在容器启动时直接调用器Refresh方法,完毕整个配置文件描写叙述的Bean的加载,可是并没有完毕依赖的注入,当第一次调用getBean方法获取Bean的时候,假设Bean是单例的会完毕Bean依赖关系的注入,而且缓存。假设Bean是多例的。则每次都会create一个新Bean,并完毕这个Bean依赖注入。

二、Spring AOP体系学习总结:

要理解AOP总体的逻辑须要理解一下Advice,Pointcut,Advisor的概念以及他们的关系。

Advice是为Spring Bean提供增强逻辑的接口,提供了多种方法增强的方式,比方前置,后置,包裹等增强方式。看下Advice的类体系结构图:

图中定义了主要有3中类型的Advice,各自是BeforeAdvice,AfterAdvice 和 Interceptor,BeforeAdvice就是定义的就是方法的前置织入逻辑。AfterAdvice就是方法的后置织入逻辑。MethodInteceptor定义的是方法的包裹逻辑。想要分析其原理。先要看看怎么用,看一个应用的DEMO:

AfterAdvice.class:
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("这个是 AfterReturning 方法!");
}
} BeforeAdvice.class:
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("这是BeforeAdvice的before方法!");
}
} CompareInterceptor.class
public class CompareInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = null;
String stu_name = invocation.getArguments()[0].toString();
if ( stu_name.equals("dragon")){
//假设学生是dragon时,运行目标方法,
result= invocation.proceed();
} else{
System.out.println("此学生是"+stu_name+"而不是dragon,不批准其增加.");
}
return result;
}
}

以上定义的各自是目标方法的前置逻辑,后置逻辑,及包裹逻辑。

目标类接口:
public interface IStudent {
public void addStudent(String name);
} 目标实现类:
public class StudentImpl implements IStudent {
@Override
public void addStudent(String name) {
System.out.println(name);
}
}

Bean定义的配置文件:

<beans>
<bean id="beforeAdvice" class="aop.demo.demo1.BeforeAdvice"></bean>
<bean id="afterAdvice" class="aop.demo.demo1.AfterAdvice"></bean>
<bean id="compareInterceptor" class="aop.demo.demo1.CompareInterceptor"></bean>
<bean id="studenttarget" class="aop.demo.demo1.StudentImpl"></bean>
<bean id="student" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>aop.demo.demo1.IStudent</value>
</property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>compareInterceptor</value>
</list>
</property>
<property name="target">
<ref bean="studenttarget"/>
</property>
</bean>
</beans> 測试驱动类:<br>
public class DriverTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ctx = new FileSystemXmlApplicationContext("/src/main/java/aop/demo/applicationContext.xml");
IStudent person = (IStudent)ctx.getBean("student");
//person.addStudent("dragon");
person.addStudent("javadragon");
}
} //运行结果:<br>
这是BeforeAdvice的before方法! 此学生是javadragon而不是dragon,不批准其增加.
这个是 AfterReturning 方法!

从上面的DEMO能够看到一共配置了 2个Advice和 1个Interceptor,然后这些配置都是作为 ProxyFactoryBean的属性存在的。上文中已经提到FactgoryBean概念。容器在获取ProxyFactoryBean的时候事实上是调用其 getObject方法。正式这个调用完毕了代理逻辑的编织。先看下这个ProxyFactoryBean getObjec方法的代码。

public Object getObject() throws BeansException {
//初始化通知器链
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
} private synchronized Object newPrototypeInstance() {
// In the case of a prototype, we need to give the proxy
// an independent instance of the configuration.
// In this case, no proxy will have an instance of this object's configuration,
// but will have an independent copy.
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
} ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
copy.setInterfaces(
ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));
}
copy.setFrozen(this.freezeProxy); if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}

以上两个方法就是ProxyFactoryBean获代替理对象的入口方法。详细的获取流程以下时序图表述一下:

通过以上时序图能够看到,详细代理类的生成是有 JDKDynamicAopProxy 和 CglibProxy来完毕的。

详细使用哪种动态代理的生成方式是依据目标类是否有接口 isInterface来推断的。相应DefaultAOPProxyFactory
生成代理类的方法例如以下:

//这里有两个分支选择。一个是选择JDK的Proxy动态代理的实现。一个使用Cglib的实现。

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()) {
return new JdkDynamicAopProxy(config);
}
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. " +
"Add CGLIB to the class path or specify proxy interfaces.");
}
//假设不是接口类要生成Proxy,那么使用CGLIB来生成
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

由上文可知Advice是定义的Bean的前后的织入逻辑,那么这个织入逻辑是什么时候融入到方法中的呢。那就须要详细分析一下JDKDynamicAopProxy和Cglib2AopProxy了。

先上两张张AopProxy的类图:

AopProxy的依赖类图:



由上图可见AopProxy是间接仅仅用了Advice来完毕Bean的编织强化操作,详细代码例如以下:

JdkDynamicAopProxy的invoke方法:
/**
* Implementation of <code>InvocationHandler.invoke</code>.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null; try {
//假设目标对象没有实现Object类的基本方法:equals
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
//假设目标对象没有实现Object类的基本方法:hashCode
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
} if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
//依据代理对象的配置来调用服务
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
} // May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
} // 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.
//假设未定义拦截器,那么就直接调用target相应的方法
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.
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
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();
} // Massage return value if necessary.
if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

JdkDynamicAopProxy实现了JDK定义的 InvocationHandler接口,在实现JDK的动态代理的时候时间自身传入代理逻辑完毕Bean的强化。这个invoke方法就是强化Bean逻辑的核心。从代码中能够看到在详细运行被代理类的目标方法的时候,先是获取了一个连接器链:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

然后再运行详细方法的时候。先会递归的调用拦截器的逻辑,我们定义的Advice逻辑和Interceptor逻辑就是封装在这些Interceptor里面的。拦截器链的调用织如逻辑能够看下ReflectiveMethodInvocation 这个类的 proceed方法:

//递归调用拦截器链
//无论是JdkDynamicAopProxy还是Cglib2Aop都是要用的这种方法运行的拦截器链
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引-1的拦截器開始调用。并按序递增。假设拦截器链中的拦截器迭代调用完毕,这里開始调用target的函数,这个函数是通过反射机制完毕的。
// 详细实如今AopUtil.invokeJoinpointUsingReflection方法中。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
//这步才真正的调用目标方法
return invokeJoinpoint();
} 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)) {
//这个里面也会运行Proceed方法完毕,Advice行为的调用
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);
}
}

这种方法完毕了我们定义的拦截器的递归调用。详细能够看代码上的凝视。至于Cglib2AopProxy的拦截方式和JDkDynamicAopProxy能够说是如出一辙的,Cglib2AopProxy的强化逻辑能够看其内部类DynamicAdvisedInterceptor定义的intercept方法:

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

    private AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
} public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be <code>null</code>. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool.
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
//假设没有拦截器则直接调用目标方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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.
retVal = methodProxy.invoke(target, args);
}
else {
// We need to create a method invocation...
// 假设拦截器有设置则对其进行拦截
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

而这里定义的MethodInvocation相应的proceed方法和JDKDynamicAopProxy相应的同一个proceed方法。

至此Spring 容器中Bean的强化逻辑就看完了。细心的同学可能会发现一个问题就是上面那个DEMO里,为什么把Advice配置在了Interceptor的属性里呢?:

 <property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>compareInterceptor</value>
</list>
</property>

这种配置无非是把Advice当做了拦截器注入,事实上这里面还存在一个适配器的概念:

 是这些Adapter将我们定义的Advice转换成了Interceptor,然后再代理类目完毕拦截调用,看个源代码:

MethodBeforeAdviceAdapter的适配转换实现:

/**
* Adapter to enable {@link org.springframework.aop.MethodBeforeAdvice}
* to be used in the Spring AOP framework.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable { public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
} public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}

正是这些适配器完毕了我们定义的Advice和Inteceptor的转换。

由此可见Advice和Interceptor有着非常强的血缘关系,以下看个Advice和Inteceptor的关系图:

Advice就讲到这吧,以下看下Pointcut的概念:

Pointcut(切点)决定Advice应该作用于哪个连接点,也就说通过Pointcut来定义须要增强的方法集合,这些集合的选取能够依照一定的规则来完毕,说白了就是制定那些方法须要增强。以下是Pointcut的类继承体系结构:

Pointcut不想多说,看个实际使用的配置文件的样例:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
default-autowire="byName"> <!-- ==============================利用spring自己的aop配置================================ -->
<!-- 声明一个业务类 -->
<bean id="baseBusiness" class="aop.demo.demo2.BaseBusiness" /> <!-- 声明通知类 -->
<bean id="baseBefore" class="aop.demo.demo2.BaseBeforeAdvice" />
<bean id="baseAfterReturn" class="aop.demo.demo2.BaseAfterReturnAdvice" />
<bean id="baseAfterThrows" class="aop.demo.demo2.BaseAfterThrowsAdvice" />
<bean id="baseAround" class="aop.demo.demo2.BaseAroundAdvice" /> <!-- 指定切点匹配类 -->
<bean id="pointcut" class="aop.demo.demo2.Pointcut" /> <!-- 包装通知,指定切点 -->
<bean id="matchBeforeAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="pointcut" />
</property>
<property name="advice">
<ref bean="baseBefore" />
</property>
</bean> <!-- 使用ProxyFactoryBean 产生代理对象 -->
<bean id="businessProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理对象所实现的接口 ,假设有接口能够这样设置 -->
<property name="proxyInterfaces">
<value>aop.demo.demo2.IBaseBusiness</value>
</property> <!-- 设置目标对象 -->
<property name="target">
<ref local="baseBusiness" />
</property>
<!-- 代理对象所使用的拦截器 -->
<property name="interceptorNames">
<list>
<!-- 这个Advisor之所以能够设置在这里。是由于会有AdvisorAdapter做转换适配 -->
<value>matchBeforeAdvisor</value>
<value>baseAfterReturn</value>
<value>baseAround</value>
</list>
</property>
</bean>
</beans>

通过配置文件能够看出来通过Advisor将 pointcut和Advice整合在了一起。然后将这些Advisor注入到ProxyFactoryBean的体系中。这样这个Advisor就变成了有条件的链接器,pointcut就是条件。Advice就是相应的运行逻辑,而Advisor就是整合这两个实体的一个关联关系。

以上学习的代码版本号是: 代码版本号是Spring V3.1.1 svn地址是:https://github.com/lantian0802/spring-framework.git/tags/v3.1.1.RELEASE

Spring IOC及AOP学习总结的更多相关文章

  1. Spring入门IOC和AOP学习笔记

    Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容 ...

  2. 【转】spring - ioc和aop

    [转]spring - ioc和aop 1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对 ...

  3. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  4. 框架源码系列六:Spring源码学习之Spring IOC源码学习

    Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的  1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...

  5. spring - ioc和aop

    1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new ...

  6. Spring ioc与aop的理解

    一 spring的特点 1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易 ...

  7. spring IOC与AOP

    Spring IOC容器 spring IOC 容器有两种,分别是 BeanFactory 容器和 ApplicationContext 容器. BeanFactory如下: /*第一步,利用Clas ...

  8. Spring IOC、AOP、Transaction、MVC小结

    1.IOC.AOP:把对象交给Spring进行管理,通过面向切面编程来实现一些“模板式”的操作,使得程序员解放出来,可以更多的关注业务实现.                             - ...

  9. BeanPostProcessor —— 连接Spring IOC和AOP的桥梁

    之前都是从大Boss的视角,来介绍Spring,比如IOC.AOP. 今天换个视角,从一个小喽啰出发,来加深对Spring的理解. 这个小喽啰就是, BeanPostProcessor (下面简称 B ...

随机推荐

  1. for_each的各种情况下的使用详解

    原创作者:http://oomusou.cnblogs.com 配合<C++ Template>(简体中文)使用 http://download.csdn.net/detail/qq239 ...

  2. accept系统调用内核实现

    用户态对accept的标准使用方法: if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_siz ...

  3. (1)前言——(10)jquery项目的历史(History of the jQuery project)

    This book covers the functionality and syntax of jQuery 1.6.x, the latest version at the time of wri ...

  4. 碰撞回避算法(一) Velocity Obstacle

    碰撞回避是机器人导航,游戏AI等领域的基础课题.几十年来,有很多算法被提出.注意这里主要指的是局部的碰撞回避算法.尽管和全局的路径规划算法(A*算法等)有千丝万缕的联系.可是还是有所不同的(局部的碰撞 ...

  5. ftk学习记(对话框篇)

    [声明:版权全部,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面谈到了输入法,首先看一看效果. 上面有4个输入框,大家能够分别试试,看看效果怎样. 今天,我 ...

  6. uva 699

    #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #i ...

  7. 解决 Android SDK Manager不能下载旧版本的sdk的问题

    解决无法使用Android SDK  Manager下载SDK开发包的解决办法. 当我们在官网下载google的集成ADT,也就是adt-bundle-linux-x86.zip开发包,进行解压, 打 ...

  8. Hacker News网站的文章排名算法工作原理

    In this post I'll try to explain how Hacker News ranking algorithm works and how you can reuse it in ...

  9. OpenVPN多处理之-netns容器与iptables CLUSTER

    假设还是沉湎于之前的战果以及强加的感叹,不要冥想,将其升华. 1.C还是脚本 以前,我用bash组织了复杂的iptables,ip rule等逻辑来配合OpenVPN,将其应用于差点儿全部能够想象得到 ...

  10. 『openframeworks』shader制作三角形马赛克效果

    不久前做了六边形马赛克的效果,很有意思,乘热打铁,弄了个三角形马赛克. 首先肯定是等边三角形,这样才能真正的无缝拼接.观察发现,三角形可以拼接成之前做个的六边形. 如下图: 我们可以发现6个三角形正好 ...