用过spring的朋友都知道spring的强大和高深,都觉得深不可测,其实当你真正花些时间读一读源码就知道它的一些技术实现其实是建立在一些最基本的技术之上而已;例如AOP(面向方面编程)的实现是建立在CGLib提供的类代理和jdk提供的接口代理,IOC(控制反转)的实现建立在工厂模式、java反射机制和jdk的操作XML的DOM解析方式.

       下面来对spring源码中的基本技术进行深入的剖析:先来说说AOP的实现,其实AOP就靠代理模式实现的,如:org.springframework.aop.framework.ProxyFactoryBean,看一下它实现的接口

public class ProxyFactoryBean extends ProxyCreatorSupport implements
FactoryBean, BeanClassLoaderAware, BeanFactoryAware { public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton())//是否是单例的,spring中有单例和多例两种情况
return getSingletonInstance();//创建一个单例的代理对象
if (targetName == null)
logger
.warn("Using non-singleton proxies with singleton targets is often undesirable. Enable prototype proxies by setting the 'targetName' property.");
return newPrototypeInstance();///创建一个多例的代理对象,这是默认情况
} 其中有一个FactoryBean接口,这个接口中的getObject()方法起着连接作用,在WebApplicationContext调用getBean(String beanName)使用首先调用FactoryBean的getObject()返回一个代理对象实例,在spring的代理应用场所中FactoryBean是必不可少的。 咱们继续跟踪: private synchronized Object newPrototypeInstance() {
if (logger.isTraceEnabled())
logger.trace((new StringBuilder(
"Creating copy of prototype ProxyFactoryBean config: "))
.append(this).toString());
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());//委托给代理工厂创建代理
TargetSource targetSource = freshTargetSource();//对被代理对象的封装
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
if (autodetectInterfaces && getProxiedInterfaces().length == 0
&& !isProxyTargetClass())
copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource
.getTargetClass(), proxyClassLoader));//设置被代理的接口
copy.setFrozen(freezeProxy);
if (logger.isTraceEnabled())
logger
.trace((new StringBuilder(
"Using ProxyCreatorSupport copy: ")).append(copy)
.toString());
return getProxy(copy.createAopProxy()); //调用代理工厂创建代理
} protected Object getProxy(AopProxy aopProxy) {
return aopProxy.getProxy(proxyClassLoader);//创建代理对象
} 下面是ProxyCreatorSupport 的一些方法
public class ProxyCreatorSupport extends AdvisedSupport { public ProxyCreatorSupport() {
listeners = new LinkedList();
active = false;
aopProxyFactory = new DefaultAopProxyFactory();//默认代理工厂
} public AopProxyFactory getAopProxyFactory() {
return aopProxyFactory;
} protected final synchronized AopProxy createAopProxy() {
if (!active)
activate();
return getAopProxyFactory().createAopProxy(this); //代理工厂创建代理
} 通过以上的跟踪就知道代理对象是被代理工厂创建的,代理对象对被代理对象进行代理,所以要分析代理对象的创建过程就必须从代理工厂入手,下面我们继续跟踪代理工厂DefaultAopProxyFactory。 public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { //CGLib代理工厂
private static class CglibProxyFactory { public static AopProxy createCglibProxy(AdvisedSupport advisedSupport) {
return new Cglib2AopProxy(advisedSupport);//创建CGbli代理对象
} private CglibProxyFactory() {
}
} public DefaultAopProxyFactory() {
} //代理工厂创建代理对象的具体代码 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())//如果被代理对象是现实了接口的话就使用jdk的接口代理模式否则使用CGLib提供的类代理模式
return new JdkDynamicAopProxy(config);//创建jdk动态代理
if (!cglibAvailable)
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.");
else
return CglibProxyFactory.createCglibProxy(config);//创建cglib动态代理
} else {
return new JdkDynamicAopProxy(config);//创建jdk动态代理
}
} 通过上面的代码分析知道了spring预备了两种代理模式基于ASM字节码操作的CGLib提供的类代理和jdk提供的接口代理。下面就对这两种代理模式再进行深入的剖析: 剖析一JdkDynamicAopProxy源码: 看一下实现接口InvocationHandler,这是jdk代理中调用处理程序,关于他可以参考其他日志这里不再详细讲解。
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler,
Serializable { public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled())
logger.debug((new StringBuilder(
"Creating JDK dynamic proxy: target source is ")).append(
advised.getTargetSource()).toString()); //这是我们所熟悉的jdk接口代理的一些代码
Class proxiedInterfaces[] = AopProxyUtils
.completeProxiedInterfaces(advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
} //这个方法中调用处理程序的invoke方法将会把调用处理委托给方法拦截器MethodInterceptor(也是环绕通知)
public Object invoke(Object proxy, Method method, Object args[])
throws Throwable
{ target = targetSource.getTarget();//被代理对象出现了
if(target != null)
targetClass = target.getClass();
List chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if(chain.isEmpty())
{
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
} else
{ MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();//这里将调用方法拦截器,具体看下面的代码
} } public class ReflectiveMethodInvocation implements ProxyMethodInvocation,
Cloneable { public Object proceed() throws Throwable {
if (currentInterceptorIndex == interceptorsAndDynamicMethodMatchers
.size() - 1)
return invokeJoinpoint();
Object interceptorOrInterceptionAdvice = interceptorsAndDynamicMethodMatchers
.get(++currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(method, targetClass, arguments))
return dm.interceptor.invoke(this);//方法拦截器被调用
else
return proceed();
} else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice)
.invoke(this);//方法拦截器被调用
}
} } 到现在为止关于代理对象的创建过程的跟踪已近基本结束除了CGLib,现在总结一下调用路线:ProxyFactoryBean调用AOPProxyFactory创建代理AOPProxy,AOPProxy现实对被代理对象的代理。综合上面的代码可以看出spring的代理的原理,其实就是对JDK和CGLib进行封装和扩展,把他们的InvocationHandler调用处理程序委托给MethodBeforeAdvice(前通知),ReturnAfterAdvice(后通知),MethodInterceptor(环绕通知)。 下面我们来剖析一下org.springframework.transaction.interceptor.TransactionProxyFactoryBean。 TransactionProxyFactoryBean是对事物进行控制,具体来说他就是将需要应用事物控制的类进行代理,然后当调用被代理对象的方法时实现方法拦截器的事物拦截器就会检查该类的方法是否符合事物属性的规则,如果符合那么事物拦截器就会调用事物管理器发起事物。下面看一下源代码来证实一下: public class TransactionProxyFactoryBean extends
AbstractSingletonProxyFactoryBean implements BeanFactoryAware {
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();//这是一个实现拦截器的事物拦截器 public TransactionProxyFactoryBean() {
} public void setTransactionManager(
PlatformTransactionManager transactionManager) {
transactionInterceptor.setTransactionManager(transactionManager);//这里给事物拦截器设置一个事物管理器用于发起事物
} public void setTransactionAttributes(Properties transactionAttributes) {
transactionInterceptor.setTransactionAttributes(transactionAttributes);//这里给事物拦截器设置一些事物属性就是事物的规则用于检查一个类的方法是否可以进行事物控制
} public void setTransactionAttributeSource(
TransactionAttributeSource transactionAttributeSource) {
transactionInterceptor
.setTransactionAttributeSource(transactionAttributeSource);
} 我们在看一下他的父类: 实现接口有FactoryBean接口,这个接口上面已经提到过应该有些印象吧。InitializingBean 接口用于初始化工作,在实例化WebApplicationContext之后解析xml时会调用到。
public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
implements FactoryBean, BeanClassLoaderAware, InitializingBean { //同样是在WebApplicationContext的getBan()方法调用时调用它来获取已经创建好的代理对象,这和上面有些不同的是代理对象不是在调用是创建而是在初始化时创建,具体看初始化方法
public Object getObject() {
if (proxy == null)
throw new FactoryBeanNotInitializedException();
else
return proxy;
} //InitializingBean 接口的初始化方法用于创建代理对象 public void afterPropertiesSet() {
if (target == null)
throw new IllegalArgumentException("Property 'target' is required");
if (target instanceof String)
throw new IllegalArgumentException(
"'target' needs to be a bean reference, not a bean name as value");
if (proxyClassLoader == null)
proxyClassLoader = ClassUtils.getDefaultClassLoader();
ProxyFactory proxyFactory = new ProxyFactory();//创建代理工厂
if (preInterceptors != null) {
Object aobj[];
int k = (aobj = preInterceptors).length;
for (int i = 0; i < k; i++) {
Object interceptor = aobj[i];
proxyFactory.addAdvisor(advisorAdapterRegistry
.wrap(interceptor));//对拦截器进行包装
} }
proxyFactory.addAdvisor(advisorAdapterRegistry
.wrap(createMainInterceptor()));//对拦截器进行包装
if (postInterceptors != null) {
Object aobj1[];
int l = (aobj1 = postInterceptors).length;
for (int j = 0; j < l; j++) {
Object interceptor = aobj1[j];
proxyFactory.addAdvisor(advisorAdapterRegistry
.wrap(interceptor));//对拦截器进行包装
} }
proxyFactory.copyFrom(this);
TargetSource targetSource = createTargetSource(target);//包装被代理对象
proxyFactory.setTargetSource(targetSource);
if (proxyInterfaces != null)
proxyFactory.setInterfaces(proxyInterfaces);//设置被代理对象实现的接口
else if (!isProxyTargetClass())
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(
targetSource.getTargetClass(), proxyClassLoader));
proxy = proxyFactory.getProxy(proxyClassLoader);//创建代理对象
}
} 这里的代理对象创建过程和上面的基本一样,就不在啰嗦了有兴趣的可以自己去看看。 现在总结一下事物是被事物拦截器所调用和控制的,事物管理器是被事物拦截器调用和控制的,代理就是一种来实现这种事物控制的方式和机制而已。这个AOP类似。 http://bbs.csdn.net/topics/390100539

Spring如何实现IOC和AOP的,说出实现原理。的更多相关文章

  1. 详谈 Spring 中的 IOC 和 AOP

    这篇文章主要讲 Spring 中的几个点,Spring 中的 IOC,AOP,下一篇说说 Spring 中的事务操作,注解和 XML 配置. Spring 简介 Spring 是一个开源的轻量级的企业 ...

  2. Spring核心思想Ioc和Aop (面试)

    Spring核心思想Ioc和Aop (面试) 注意: Ioc和Aop并不是Spring提出的,在Spring之前就已经存在,Spring只是在技术层面给这两个思想做了非常好的实现. 1 Ioc 1.1 ...

  3. Spring学习笔记IOC与AOP实例

    Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...

  4. Spring入门导读——IoC和AOP

    和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(I ...

  5. Spring(1) --入门(IoC,AOP)

    说说你对spring的理解? Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题.Spring框架主要提供了IoC容器 ...

  6. Spring中的IOC\DI\AOP等概念的简单学习

    IoC(Inversion of Control,控制反转).这是spring的核心,贯穿始终, 所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.Spr ...

  7. spring框架DI(IOC)和AOP 原理及方案

    http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html http://www.oschina.net/code/snippe ...

  8. Spring中的IOC和AOP是什么含义,他们在项目中起到什么作用,并举例说明?

    IOC:控制反转,是一种设计模式.一层哈尼是控制权的转移:由传统的在程序中控制并依赖转移到容器赖控制:第二是依赖注入:将相互以来的对象分离,在Spring配置文件中描述他们的依赖关系.他们的依赖关系只 ...

  9. 理解Spring中的IOC和AOP

    我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过ses ...

  10. 【转】Spring的中IoC及AOP

    1. Spring介绍 Spring是轻量级的J2EE应用程序框架.Spring的核心是个轻量级容器(container),实现了IoC(Inversion of Control)模式的容器,Spri ...

随机推荐

  1. java中如何将string转化成long

  2. 【Ajax 1】Ajax与传统Web开发的区别

    导读:从用户体验度的角度来说,利用Ajax进行开发的网站,其体验度高于利用传统Web开发技术,那么,是什么因素导致了这一现象呢?难道说Ajax开发,就一定优于传统Web技术吗?本篇文章,将主要介绍Aj ...

  3. 亲历dataguard的一些经验问答题

    问题1:是否log_archive_dest_n=service中进程使用lgwr时(如log_archive_dest_2='service=DBSTD LGWR SYNC'),备库就一定要建立st ...

  4. 【优先级队列】Southwestern Europe Regional Contest Canvas Painting

    https://vjudge.net/contest/174235#problem/D [题意] 给定n个已知size的帆布,要给这n块帆布涂上不同的颜色,规则是这样的: 每次选择一种颜色C 对于颜色 ...

  5. NodeJS仿WebApi路由

    用过WebApi或Asp.net MVC的都知道微软的路由设计得非常好,十分方便,也十分灵活.虽然个人看来是有的太灵活了,team内的不同开发很容易使用不同的路由方式而显得有点混乱. 不过这不是重点, ...

  6. 解决ssh无操作自动断开[转载,已经验证]

    用SSH远程,如果几分钟没有任何操作,连接就会断开,必须重新登陆才行,非常麻烦,一般修改2个地方3项即可解决问题: 1.终端键入:echo $TMOUT       如果显示空白,表示没有设置,等于使 ...

  7. 在d盘中创建一个文件夹 在文件夹里创建三个txt文本

    import java.io.File; import java.io.IOException; public class FileDemo { public static void main(Str ...

  8. 转 linux socket的select函数例子

    使用select函数可以以非阻塞的方式和多个socket通信.程序只是演示select函数的使用,功能非常简单,即使某个连接关闭以后也不会修改当前连接数,连接数达到最大值后会终止程序. 1. 程序使用 ...

  9. 关于oracle存储过程的若干问题备忘

    1.在oracle中,数据表别名不能加as,如: select a.appname from appinfo a;-- 正确select a.appname from appinfo as a;-- ...

  10. JAVA 比较两张图片的相似度的代码

    原文:http://www.open-open.com/code/view/1448334323079 import java.awt.image.BufferedImage; import java ...