AOP和IOC的实现原理(用到的设计模式)
文章来源:http://blog.csdn.NET/longyulu/article/details/36174979
用过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类似。
AOP和IOC的实现原理(用到的设计模式)的更多相关文章
- springmvc 运行原理 Spring ioc的实现原理 Mybatis工作流程 spring AOP实现原理
SpringMVC的工作原理图: SpringMVC流程 . 用户发送请求至前端控制器DispatcherServlet. . DispatcherServlet收到请求调用HandlerMappin ...
- Spring(二)IOC底层实现原理
IOC原理 将对象创建交给Spring去管理. 实现IOC的两种方式 IOC配置文件的方式 IOC注解的方式 IOC底层实现原理 底层实现使用的技术 1.1 xml配置文件 1.2 dom4j解析xm ...
- AOP和IOC的作用
IOC:控制反转,是一种设计模式.一层含义是控制权的转移:由传统的在程序中控制依赖转移到由容器来控制:第二层是依赖注入:将相互依赖的对象分离,在spring配置文件中描述他们的依赖关系.他们的依赖关系 ...
- AOP和IOC理解
在百度上看到一篇很有意思的文章,是对AOP的一种解释,如下:(摘自:百度文库的 AOP和IOC最容易理解的说明(Spring知识小计)): IOC,依赖倒置的意思, 所谓依赖,从程序的角度看,就是比如 ...
- spring框架的IOC的底层原理
1.IOC概念:spring容器创建对象并管理 2.IOC的底层原理的具体实现: 1)所使用的技术: (1). dom4j解析xml配置文件 (2).工厂设计模式(解耦合) (3).反射 第一步:配置 ...
- IOC的实现原理—反射与工厂模式的结合
反射机制概念 我们考虑一个场景,如果我们在程序运行时,一个对象想要检视自己所拥有的成员属性,该如何操作?再考虑另一个场景,如果我们想要在运行期获得某个类的Class信息如它的属性.构造方法.一般方 ...
- Spring源码学习之IOC容器实现原理(一)-DefaultListableBeanFactory
从这个继承体系结构图来看,我们可以发现DefaultListableBeanFactory是第一个非抽象类,非接口类.实际IOC容器.所以这篇博客以DefaultListableBeanFactory ...
- SpringBoot AOP 与 IoC
Spring的核心就是AOP与IoC,想要学习SpringBoot,首先得理解这些概念: AOP(Aspect Oriented Programming 面向切面编程) IoC(Inversion o ...
- AOP和IOC的作用(转)
AOP和IOC的作用 转载▼ IOC:控制反转,是一种设计模式.一层含义是控制权的转移:由传统的在程序中控制依赖转移到由容器来控制:第二层是依赖注入:将相互依赖的对象分离,在spring配置文 ...
随机推荐
- 多个Excel文件快速导入到DB里面
1 . 文件比较多,需要把这么多的数据都导入到DB里面,一个个导入太慢了,能想到的是先把数据整个到一个Excel中,然后再导入 2. 第一步准备合并Excel,新建一个新的excel,命名为total ...
- “maven编码gbk的不可映射字符”解决办法
一.问题描述 Eclipse中使用Maven编译项目源代码时,如下的错误 java源代码在Eclipse中显示是没有任何错误的,可是执行"maven install"命令编译项目时 ...
- reset 单个文件 回退
git将单个文件恢复到历史版本的正确方法如下: git reset commit_id 文件路径 git checkout -- 文件路径
- js、css引用文件的下载方式
js.css引用文件的下载方式 一.测试(chrome):1.直接使用<script...>.<link...>标签来混合引入脚本文件和css文件, <script as ...
- MySQL 主从配置
mysql主从复制指两个服务器之间数据库的同步,当主服务器的数据进行了变更,从服务器也会自动更新,其过程是通过bin-log日志实现的,本质是binlog日志的传输. mysql主从分两个角色 1.主 ...
- 深度解析正则表达式exec和match两者使用的异同以及要注意的地方
1.match match方法属于String正则表达方法. 语法: str.match(regexp) str:要进行匹配的字符串. regexp:一个正则表达式(或者由RegExp()构造成的正则 ...
- 异常:java.io.IOException: Too many open files:
原因: 操作系统的中打开文件的最大句柄数受限所致,常常发生在很多个并发用户访问服务器的时候.因为为了执行每个用户的应用服务器都要加载很多文件(new一个socket就需要一个文件句柄),这就会导致打开 ...
- Oracle 11g中修改默认密码过期天数和锁定次数
Oracle 11g中修改默认密码过期天数和锁定次数 密码过期的原因一般有两种可能: 一.由于Oracle中默认在default概要文件中设置了"PASSWORD_LIFE_TIME=180 ...
- VS2013 ViewData ViewBag Ajax等关键词报错(当前上下文不存在名称)而且不提示也点不出来,但是可以正常运行,
这个多数问题是因为 视图 的Web.config 内的配置问题 在Views文件夹下 有一个Web.config文件,把里面的版本号(System.Web.Mvc, Version=5.2.2.0) ...
- ue4 ios
project settings package 可以指定非APK打包,确定资源是否发布 可以指定content下某个目录所有文件(非.uassert)都打包 ios环境下fopen打开文件需要指定路 ...