Spring中的ignoreDependencyInterface 和 ignoreDependencyType

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<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
//......
public void ignoreDependencyInterface(Class<?> ifc) {
		this.ignoredDependencyInterfaces.add(ifc);
}

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

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. 配置文件<context:annotation-config/>开启注解

在这里插入图片描述

  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中的<context:annotation-config>,并且增加default-autowire="byType",其值为“byType",意思是按照对象的类型进行装配。
    在这里插入图片描述

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

在这里插入图片描述

小结

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

ignoreDependencyInterface

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

/**
	 * Ignore the given dependency interface for autowiring.
	 * <p>This will typically be used by application contexts to register
	 * dependencies that are resolved in other ways, like BeanFactory through
	 * BeanFactoryAware or ApplicationContext through ApplicationContextAware.
	 * <p>By default, only the BeanFactoryAware interface is ignored.
	 * For further types to ignore, invoke this method for each type.
	 * @param ifc the dependency interface to ignore
	 * @see org.springframework.beans.factory.BeanFactoryAware
	 * @see org.springframework.context.ApplicationContextAware
	 */
	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<Class<?>> 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标签中,如果增加<property >标签会导致这两个方法失效,目前不知道是什么原因,此处留个坑,日后来填!!!

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

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值