最新公告:

中华视窗是诚信为本,市场在变,我们的诚信永远不变...

中华视窗

咨询热线

400-123-4657

公司动态

当前位置: 首页 > 新闻动态 > 公司动态

Spring动态代理的生成-如何判断是使用JDK动态代理还是CGlib代理

添加时间:2024-02-11

/

前言

在上一篇文章中讲到了是如何获取对应的Bean的增强,然后本次主要讲解一下如何在获取到增强后创建代理的。

在步入正题之前先给大家看一下创建代理的大致流程图

动态代理流程_代理动态公司名称_动态代理公司

接下来我们就回到ator.class类中的方法。

  protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果已经处理过
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
    }
    // 无需增强
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
    }
    // 给定的bean类是否是一个基础设施类,基础设施类不应该被代理,或者配置了指定的bean不需要代理
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
    }

    // 获取能够应用到当前 Bean 的所有 Advisor(已根据 @Order 排序)
    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果有 Advisor,则进行下面的动态代理创建过程
    if (specificInterceptors != DO_NOT_PROXY) {
      // 如果获取到了增强则需要针对增强进行代理
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 创建代理 JDK 动态代理或者 CGLIB 动态代理
      Object proxy = createProxy(
          bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      // 将代理对象的 Class 对象(目标类的子类)保存
      this.proxyTypes.put(cacheKey, proxy.getClass());
      //  返回这个 Bean 对象
      return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

在上一篇源码之创建AOP代理之增强器的获取文章中,主要是围绕着方法展开的,主要是获取到了所有对应Bean的增强器,并获取到了此目标Bean所匹配的,

接下来我们着手对接下来的方法进行分析,

代理动态公司名称_动态代理流程_动态代理公司

protected Object createProxy(Class beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    // 创建一个代理工厂
    ProxyFactory proxyFactory = new ProxyFactory();
    // 复制当前 ProxyConfig 的一些属性(例如 proxyTargetClass、exposeProxy)
    proxyFactory.copyFrom(this);

    // 判断是否是代理类(也就是是否开启了CGLIB代理) 默认是false
    if (proxyFactory.isProxyTargetClass()) {
      // Explicit handling of JDK proxy targets (for introduction advice scenarios)
      if (Proxy.isProxyClass(beanClass)) {
        // Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
        for (Class ifc : beanClass.getInterfaces()) {
          proxyFactory.addInterface(ifc);
        }
      }
    }
    else {
      // 如果这个 Bean 配置了进行类代理,则设置为 `proxyTargetClass` 为 `true`
      // No proxyTargetClass flag enforced, let's apply our default checks...
      if (shouldProxyTargetClass(beanClass, beanName)) {
        proxyFactory.setProxyTargetClass(true);
      }
      else {
        // 检测当前Bean 实现的接口是否包含可代理的接口 ,如果没有,则将proxyTargetClass 设置为true 表示需要进行CGLIB 提升
        evaluateProxyInterfaces(beanClass, proxyFactory);
      }
    }

    // 对入参的 advisors 进一步处理,因为其中还可能存在Advice类型 需要将他们包装成 DefaultPointcutAdvisor
    // 如果配置了 `interceptorNames` 拦截器,也会添加进来
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 代理工厂添加 Advisor 数组
    proxyFactory.addAdvisors(advisors);
    // 代理工厂设置 TargetSource 对象
    proxyFactory.setTargetSource(targetSource);
    // 对 ProxyFactory 进行加工处理,抽象方法,目前没有子类实现
    customizeProxyFactory(proxyFactory);

    //用来控制代理工厂被配置之后,是否还允许修改通知。(默认为 false) (即在代理被配置之后,不允许修改代理的配置)。
    proxyFactory.setFrozen(this.freezeProxy);
    // 这个 AdvisedSupport 配置管理器是否已经过滤过目标类(默认为 false)
    if (advisorsPreFiltered()) {
      // 设置 `preFiltered` 为 `true`
      //  这样 Advisor 们就不会根据 ClassFilter 进行过滤了,而直接通过 MethodMatcher 判断是否处理被拦截方法
      proxyFactory.setPreFiltered(true);
    }

    // 如果 bean 类未在覆盖类加载器中本地加载,则使用原始 ClassLoader
    // Use original ClassLoader if bean class not locally loaded in overriding class loader
    ClassLoader classLoader = getProxyClassLoader();
    if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
      classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
    }
    // 通过 ProxyFactory 代理工厂创建代理对象
    return proxyFactory.getProxy(classLoader);
}

接下来继续跟踪源码.();该方法创建了代理对象。

public Object getProxy(@Nullable ClassLoader classLoader) {
    // 先创建一个 AOP 代理类(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy) 其实现是在DefaultAopProxyFactory中
    // 根据 AOP 代理为目标 Bean 创建一个代理对象,并返回
    return createAopProxy().getProxy(classLoader);
}

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
      activate();
    }
    // 先获取 AOP 代理工厂,默认为 DefaultAopProxyFactory,只有这个实现
    // 然后通过它根据创建当前 AdvisedSupport 配置管理器创建一个 AOP 代理(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
    return getAopProxyFactory().createAopProxy(this);
}

紧接着我们直接来到具体实现方法的实现类ry类中。

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 判断是否满足下面条件的
    /*
     * config.isOptimize() 需要优化,默认为 `false`详细来说就是:用来控制通过CGLIB创建的代理是否使用激进的优化策略
     *       除非完全了解AOP代理如何处理优化,否则不推荐用户使用这个设置,目前这个属性仅用于CGLIB 代理,对于JDK动态代理(缺省代理)无效
     * config.isProxyTargetClass() 使用类代理,也就是使用 CGLIB 动态代理 默认为 `false`
     *      设置方式:
     * hasNoUserSuppliedProxyInterfaces(config) // 是否存在代理接口
     */
    if (!NativeDetector.inNativeImage() &&
        (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.");
      }
      // 如果目标类是一个接口或者是 java.lang.reflect.Proxy 的子类 则还是使用 JDK 动态代理,创建一个 JdkDynamicAopProxy 对象,
      // 传入 AdvisedSupport 配置管理器,并返回
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
        return new JdkDynamicAopProxy(config);
      }
      // 使用 CGLIB 动态代理,创建一个  ObjenesisCglibAopProxy 对象,传入 AdvisedSupport 配置管理器,并返回
      return new ObjenesisCglibAopProxy(config);
    }
    else {
      // 使用 JDK 动态代理,创建一个 JdkDynamicAopProxy 对象,传入 AdvisedSupport 配置管理器,并返回
      return new JdkDynamicAopProxy(config);
    }
}

JDK与Cglib的说明如何强制使用CGLIB实现AOP?添加 CGLIB 库,/cglib/*. 配置文件中加人。JDK动态代理和CGLIB字节码生成的区别?

好了到这里就讲完了是如何决定使用哪种动态代理的方式的。

微信搜索【码上遇见你】获取更多精彩内容。

联系我们

电话:400-123-4657

传真:+86-123-4567

地址:浙江 温州市 温州大道欧江大厦26188号

邮箱:admin@kakqq.cn

电话:400-123-4657 传真:+86-123-4567 地址:浙江 温州市 温州大道欧江大厦26188号
版权所有:Copyright © 2002-2024 中华视窗 版权所有 非商用版本 ICP备案编号:粤IP**********    网站地图