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 ...
随机推荐
- 几个非常实用的JQuery代码片段
jQuery是一个兼容多浏览器的javascript库,核心理念是write less,do more(写得更少,做得更多).jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用). ...
- 我的java web之路(安装)
所有的软件下载完,陪完jdk之后,迎来了一系列的安装工作... 1.安装SQL Server 2005 首先,打开ISS功能,控制面板->程序->打开或关闭windows功能 注意红框内的 ...
- Java中的事务——全局事务与本地事务
转载,原文来源 http://www.hollischuang.com Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务.这是从事务的实现角度区 ...
- 【POJ 2891】Strange Way to Express Integers(一元线性同余方程组求解)
Description Elina is reading a book written by Rujia Liu, which introduces a strange way to express ...
- UVa 1354 天平难题 (枚举二叉树)
题意: 分析: 其实刚看到这题的时候觉得很难, 以至于结束了第七章然后去做了一遍第六章树的部分.现在再做这题觉得思路并不是太难,因为总共就只有六个结点,那么只要枚举二叉树然后算出天平然后再从叶子往上推 ...
- MongoDB中WiredTiger的数据可用性设置
此文已由作者温正湖授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. MongoDB中WiredTiger的参数配置主要通过 wiredtiger_open (http://so ...
- mysql汉字转拼音函数
-- 创建汉字拼音对照临时表 CREATE TABLE IF NOT EXISTS `t_base_pinyin` ( `pin_yin_` ) CHARACTER SET gbk NOT NULL, ...
- python re 正则提取中文
需求: 提取文本中的中文和数字字母(大小写都要),即相当于删除所有标点符号. 其中new是原字符串 news = re.findall(r'[\u4e00-\u9fa5a-zA-Z0-9]',new)
- Android: java.lang.ClassCastException: android.widget.imageView cannot be cast to android.widget.textView异常解决
有时在修改xml文件时,全报这种错误,这个应该是缓存没得到及时更新导致的,可以通过以下方法解决: Eclipse tends to mess up your resources every now a ...
- [NOIP2001] 提高组 洛谷P1025 数的划分
题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...