博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AOP和IOC的实现原理(用到的设计模式)
阅读量:5091 次
发布时间:2019-06-13

本文共 9115 字,大约阅读时间需要 30 分钟。

文章来源:http://blog.csdn/longyulu/article/details/36174979

 

用过的朋友都知道spring的强大和高深,都觉得深不可测,其实当你真正花些时间读一读源码就知道它的一些技术实现其实是建立在一些最基本的技术之上而已;例如AOP(面向方面编程)的实现是建立在CGLib提供的类代理和jdk提供的接口代理,IOC(控制反转)的实现建立在工厂模式、反射机制和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类似。

转载于:https://www.cnblogs.com/yver/p/6027897.html

你可能感兴趣的文章
hibernate4.3版本构造SessionFactory方法
查看>>
Service通信详解
查看>>
前端知识体系
查看>>
职业道德素养
查看>>
MVC View与Controller分离
查看>>
php生命周期
查看>>
测试转型之路--学习ing
查看>>
java、myeclipse项目文件没有错,但是项目名有红叉叉
查看>>
关于C/C++中求最大公约数和最小公倍数的算法
查看>>
mui框架的input输入框为什么会自动触发页面刷新?
查看>>
webpack4+ 学习1
查看>>
Python学习(十三) —— 网络编程
查看>>
Flutter Image(图片)
查看>>
exists的用法
查看>>
吴裕雄 python 机器学习——集成学习梯度提升决策树GradientBoostingClassifier分类模型...
查看>>
吴裕雄--天生自然 JAVASCRIPT开发学习: JSON
查看>>
吴裕雄--天生自然 R语言开发学习:图形初阶(续一)
查看>>
伟大软件的简易3步骤
查看>>
CSS浮动(float,clear)通俗讲解
查看>>
东西很多的时候不要急,把东西先放一边
查看>>