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 ...
随机推荐
- 大数据学习——mapreduce共同好友
数据 commonfriends.txt A:B,C,D,F,E,O B:A,C,E,K C:F,A,D,I D:A,E,F,L E:B,C,D,M,L F:A,B,C,D,E,O,M G:A,C,D ...
- zoj 1109 Language of FatMouse(map)
Language of FatMouse Time Limit: 10 Seconds Memory Limit: 32768 KB We all know that FatMouse do ...
- python学习笔记--面向对象的编程和类
一.面向对象的编程 面向对象程序设计--Object Oriented Programming,简称oop,是一种程序设计思想.二.面向对象的特性类:class类,对比现实世界来说就是一个种类,一个模 ...
- Codeforces Round #277 (Div. 2 Only)
A:SwapSort http://codeforces.com/problemset/problem/489/A 题目大意:将一个序列排序,可以交换任意两个数字,但要求交换的次数不超过n,输出任意一 ...
- PHP应用日期与时间
<?php/* 时间戳 * * 1. 是一个整数 * 2. 1970-1-1 到现在的秒数 1213212121 * * 2014-02-14 11:11:11 * * 02/14/2014 1 ...
- 潘多拉的盒子(bzoj 1194)
Description Input 第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50).文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语机S-1的顺序描述.每一块的格 ...
- BZOJ1916: [Usaco2010 Open]冲浪
n<=50000个点m<=150000的带边权DAG,保证1入度0,n出度0,其他点入度出度均不为0,求:从一号点开始到n,期间有可能K<=10次随机选边走,最坏情况下总边权多少. ...
- 编程之美2015资格赛 题目2 : 回文字符序列 [ 区间dp ]
传送门 题目2 : 回文字符序列 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定字符串,求它的回文子序列个数.回文子序列反转字符顺序后仍然与原序列相同.例如字符串ab ...
- Notification通知创建
Notification通知创建 由于通知是一个远程视图,所以创建通知在状态栏显示需要用到三个主要的对象: 一.PendingIntent对象,用来承载Intent对象的,Intent对象主要是定义通 ...
- CodeForces 592C The Big Race
公倍数之间的情况都是一样的,有循环节. 注意min(a,b)>t的情况和最后一段的处理.C++写可能爆longlong,直接Java搞吧...... import java.io.Buffere ...