栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring中的ignoreDependencyInterface 和 ignoreDependencyType

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring中的ignoreDependencyInterface 和 ignoreDependencyType

文章目录
    • Spring中的ignoreDependencyInterface 和 ignoreDependencyType
      • ignoreDependencyType
        • CASE1
        • CASE2
        • CASE3
        • 小结
      • ignoreDependencyInterface
        • CASE4
        • 小结
      • 源码跟踪
      • 总结

Spring中的ignoreDependencyInterface 和 ignoreDependencyType

起因:在学习spring启动的源码过程中,发现其方法prepareBeanFactory中有大量的调用ignoreDependencyInterface方法,如下图所示

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //......
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
    //.......
  }

很好奇这个方法是做什么的,结果发现只是在Set集合中添加元素,如下图所示

private final Set> ignoredDependencyInterfaces = new HashSet<>();
//......
public void ignoreDependencyInterface(Class ifc) {
		this.ignoredDependencyInterfaces.add(ifc);
}

于是便上网查询相关的资料,发现类似的方法有两个ignoreDependencyInterface 和 ignoreDependencyType,便一探究竟。

ignoreDependencyType

根据spring的注释,翻译出来为:忽略给定的依赖类型以进行自动装配

根据字面意思,接下来我们便来试试水

CASE1
  1. 先创建两个类A.java 和 C.java,并且在xml中配置,具体如下图所示:
//A类 使用@Autowired注入C
public class A {
	@Autowired
	private C c;
  
	public A() {
		System.out.println("A初始化了");
	}
}

//C类
public class C {
	private String name;

	public C() {
		System.out.println("C初始化了");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
//启动类
public class MainAutowired {
	public static void main(String[] args) {
		ApplicationContext applicationContext1 = new ClassPathXmlApplicationContext("classpath:application.xml");
		A bean = applicationContext1.getBean(A.class);
	}
}
  1. 配置文件开启注解

  1. 首先先在正常情况下debug跑起来,能看到A类中的属性C不为Null,并且name是zhangsan

CASE2
  1. 接下来添加一个IgnoreDependencyTest类,调用beanFactory的ignoreDependencyType方法,并且在xml中配置此类。
public class IgnoreDependencyTest implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		beanFactory.ignoreDependencyType(C.class);
	}
}

  1. debug程序,发现和我们预期的不太一样,C类还是被注入进去了,难道是ignoreDependencyType无效吗?
CASE3
  1. 结合网上资料来看,在beans标签中使用default-autowire属性来注入依赖。对例子进行改造:

    去掉A.java的@Autowired

    //A类 使用@Autowired注入C
    public class A {
    	private C c;
      
    	public A() {
    		System.out.println("A初始化了");
    	}
    }
    

    去掉配置文件xml中的,并且增加default-autowire="byType",其值为“byType",意思是按照对象的类型进行装配。

  2. 其他类不改变,此时debug启动,发现A.java中的C属性为null了,ignoreDependencyType生效了,结果就符合期待了:

小结

​ 经过实验发现,发现英语中的autowiring特定指的是通过beans标签default-autowire属性来依赖注入的方式,而不是指使用@Autowired注解进行的依赖注入。区别在于,使用default-autowire会自动给所有的类都会从容器中查找匹配的依赖并注入,而使用@Autowired注解只会给这些注解的对象从容器查找依赖并注入。自动装配和@Autowired注解的装配不是同一回事。从这次例子来看,ignoreDependencyType方法和我们期待的完全一致,可以在自动装配的时候忽略C类的对象。

ignoreDependencyInterface

根据翻译可以知道:忽略给定的依赖接口以进行自动装配

	void ignoreDependencyInterface(Class ifc);

ignoredDependencyInterface方法并不是让我们在自动装配时直接忽略实现了该接口的依赖。这个方法的真正意思是忽略该接口的实现类中和接口setter方法入参类型相同的依赖。

CASE4

1.新增接口D、All类,并且在配置文件增加all的配置信息

//接口D
public interface D {
	void setA(A a);
}


//类All 实现了D并且实现了set方法
public class All implements D{
	private A a;
	private C c;
	@Override
	public void setA(A a) {
		this.a = a;
	}
	public A getA() {
		return a;
	}

	public C getC() {
		return c;
	}

	public void setC(C c) {
		this.c = c;
	}
}

  1. debug运行先注释掉//beanFactory.ignoreDependencyInterface(D.class);,可以看到a和c都是有值的

  1. 打开beanFactory.ignoreDependencyInterface(D.class);可以看到a的值为null,说明ignoreDependencyInterface生效了

小结

其意思和我们最初理解的存在一定的差距。我们最初理解是在自动装配时忽略该接口的实现,实际上是在自动装配时忽略该接口实现类中和setter方法入参相同的类型,也就是忽略该接口实现类中存在依赖外部的bean属性注入。

源码跟踪

通过跟踪源码,我们可以发现,调用ignoreDependencyInterface方法后,被忽略的接口会存储在BeanFactory的名为ignoredDependencyInterfaces的Set集合中,而调用ignoreDependencyType则存储在ignoredDependencyTypes的Set集合中,如下所示:

在该方法中,会判断给定的bean属性在依赖检测中要被排除,假如该方法返回true,也就是在依赖检测中这个bean的属性要被排除,在自动装配时就会被忽略。

protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
		return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||
				this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||
				AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
	}

其中,this.ignoredDependencyTypes.contains()就是判断我们往ignoreDependencyType集合中添加的忽略注入的类型是否存在,而AutowireUtils.isSetterDefinedInInterface就是判断ignoredDependencyInterface的相关代码了,我们继续走下去:

public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set> interfaces) {
		Method setter = pd.getWriteMethod();
		if (setter != null) {
			Class targetClass = setter.getDeclaringClass();
			for (Class ifc : interfaces) {
				if (ifc.isAssignableFrom(targetClass) && ClassUtils.hasMethod(ifc, setter)) {
					return true;
				}
			}
		}
		return false;
	}

DEBUG进来可以看到,interfaces中的D类就是我们先前定义的接口,首先获取该bean(All.java)的setter方法,如果不存在setter,直接返回false,否则判断setter的targetClass(也就是All.java)是否是interfaces中接口的子类/子接口/相同(PS:isAssignableFrom用法可自行百度),并且该interfaces中的接口是否拥有该setter方法,如果都满足,则返回true。

总结

1.ignoreDependencyType(Class class)方法只影响xml配置自动装配的依赖注入方式.

2.ignoreDependencyType方法虽然在源码中有使用,但我觉得一般情况下不会用到它,一是因为在使用过程中都希望自动注入依赖,二是因为有@AutoWired注解,可以决定哪些依赖必须注入

3.是因为目前使用最多最流行的是SpringBoot方式配置bean,xml方式将更少触及.

4.ignoreDependency方法忽略指定依赖类型的自动装配,ignoreDependency和ignoreDependencyInterface不同的是一个前者按照class类型进行忽略自动装配,后者按照接口中的set方法进行忽略自动装配.**

补充:

研究下来,也算解决了自己的困惑,但是对于spring源码中使用它的用意还没有了解到,其次如果在xml中的bean标签中,如果增加标签会导致这两个方法失效,目前不知道是什么原因,此处留个坑,日后来填!!!

参考资料:https://www.jianshu.com/p/3c7e0608ff1f?from=singlemessage

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/922074.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号