Spring如何实现IOC和AOP的,说出实现原理。
用过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的,说出实现原理。的更多相关文章
- 详谈 Spring 中的 IOC 和 AOP
这篇文章主要讲 Spring 中的几个点,Spring 中的 IOC,AOP,下一篇说说 Spring 中的事务操作,注解和 XML 配置. Spring 简介 Spring 是一个开源的轻量级的企业 ...
- Spring核心思想Ioc和Aop (面试)
Spring核心思想Ioc和Aop (面试) 注意: Ioc和Aop并不是Spring提出的,在Spring之前就已经存在,Spring只是在技术层面给这两个思想做了非常好的实现. 1 Ioc 1.1 ...
- Spring学习笔记IOC与AOP实例
Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...
- Spring入门导读——IoC和AOP
和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(I ...
- Spring(1) --入门(IoC,AOP)
说说你对spring的理解? Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题.Spring框架主要提供了IoC容器 ...
- Spring中的IOC\DI\AOP等概念的简单学习
IoC(Inversion of Control,控制反转).这是spring的核心,贯穿始终, 所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.Spr ...
- spring框架DI(IOC)和AOP 原理及方案
http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html http://www.oschina.net/code/snippe ...
- Spring中的IOC和AOP是什么含义,他们在项目中起到什么作用,并举例说明?
IOC:控制反转,是一种设计模式.一层哈尼是控制权的转移:由传统的在程序中控制并依赖转移到容器赖控制:第二是依赖注入:将相互以来的对象分离,在Spring配置文件中描述他们的依赖关系.他们的依赖关系只 ...
- 理解Spring中的IOC和AOP
我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式 IOC就是典型的工厂模式,通过ses ...
- 【转】Spring的中IoC及AOP
1. Spring介绍 Spring是轻量级的J2EE应用程序框架.Spring的核心是个轻量级容器(container),实现了IoC(Inversion of Control)模式的容器,Spri ...
随机推荐
- docker:安装tomcat
文章来源:http://www.cnblogs.com/hello-tl/p/8929879.html 0.下载镜像 # docker pull tomcat:8.5 1.复制tomcat配置 先启动 ...
- GitLab 安装和配置
一.GitLab 简介 GitLab 是一个利用Ruby on Rails 开发的开源版本控制系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. 它拥有与GitHub类 ...
- xmind 8 readme
xmind 8 readme README LICENSE XMind 3 is dual licensed under 2 open source licenses: the Ecl ...
- spring的IOC和DI
https://blog.csdn.net/fuzhongmin05/article/details/55802816 (1)IOC:控制反转,把对象创建交给spring进行配置 (2)DI:依赖注入 ...
- spring的IOC底层原理
我们调用一个类的方法,首先是User user=new User(),对象调用这个方法,user.add(),这种方法有一个缺陷就是代码的耦合度太高,比如你的servlet调用User类里的方法,需 ...
- HDU3183A Magic Lamp,和NYOJ最大的数一样
A Magic Lamp Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...
- 【贪心+二分】codeforces C. Sagheer and Nubian Market
http://codeforces.com/contest/812/problem/C [题意] 如何花最少的钱买最多的纪念品?首要满足纪念品尽可能多,纪念品数量一样花钱要最少,输出纪念品数量以及最少 ...
- bzoj 1703 [Usaco2007 奶牛排名 传递闭包
[Usaco2007 Mar]Ranking the Cows 奶牛排名 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 504 Solved: 343[ ...
- asp.net 引发类型为“System.OutOfMemoryException”的异常
asp.net 引发类型为“System.OutOfMemoryException”的异常通常发生在IIS进程获取不到内存时. 临时解决方法是: 回收IIS的应用程序池. 如果要比较好的解决办法是: ...
- The Grove(poj 3182)
题意:一个n*m(n,m<=50)的矩阵有一片连着的树林,Bessie要从起始位置出发绕林子一圈再回来,每次只能向横着.竖着或斜着走一步.问最少需多少步才能完成. /* 如果我们用搜索来写的话, ...