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 ...
随机推荐
- python基础知识04-散列类型运算优先级和逻辑运算
散列类型 1.集合 定义集合 se = {1,2,3,4} se = set()定义空集合 se = {1,3,5,7} se2 = {1,3,8,9} se & se2 {1,3} 交集 s ...
- python-with管理文件上下文(基本文件操作)
什么是文件 文件是操作系统为用户提供的一个读写硬盘的虚拟单位,文件的操作就是文件的读.写. 操作过程:当我们双击文件 -<- 操作系统接收到指令请求(将用户或应用程序的读写操作转换成集体的硬盘指 ...
- LINUX常见小问题汇总
1. crontab的备份与恢复 备份crontab文件: crontab -l > $HOME/mycron 恢复丢失的crontab文件: 如果不小心误删了crontab文件,假设你在自己的 ...
- HDU-5532//2015ACM/ICPC亚洲区长春站-重现赛-F - Almost Sorted Array/,哈哈,水一把区域赛的题~~
F - Almost Sorted Array Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & ...
- AI Gossip
本文作者:七牛云人工智能实验室-林亦宁原文地址:https://zhuanlan.zhihu.com/p/26168331 什么是智能 回到几万年前的东非大草原,谁能意识到,那个到处被欺负的,被表哥从 ...
- docker改变镜像源
sudo echo “DOCKER_OPTS=\”\$DOCKER_OPTS –registry-mirror=http://your-id.m.daocloud.io -d\”” >> ...
- android中的OnClickListener两种实现方式
android的activity点击事件中,通过OnClickListener来实现,要实现点击事件有两种方式 1.通过定义一个OnClickListener的内部类来实现 The example b ...
- poj2767,单向连通图判定,缩点+重新建图+新图DFS
/*该题被博客里标记为中等题,30分钟内1A,掌握了算法就简单了,单向连通图判定,单向连通图缩点 后必然唯一存在出度为0的点和入度为0的点,并且从入度为0的点出发,可以遍历所有点后到达出度为0点 (一 ...
- Codeforces 659B Qualifying Contest【模拟,读题】
写这道题题解的目的就是纪念一下半个小时才读懂题...英文一多读一读就溜号... 读题时还时要静下心来... 题目链接: http://codeforces.com/contest/659/proble ...
- vue学习001 --环境搭建
系统 : win cmd: cmder 链接:https://cmder.net/ 1.安装node.js 链接地址: http://cdn.npm.taobao.org/dist/node/v10. ...