一、xml时代

先定义两个动物类:

spring配置bean之前替换配置属性 spring替换已加载bean_java

spring配置bean之前替换配置属性 spring替换已加载bean_spring_02

创建一个动物园类:

spring配置bean之前替换配置属性 spring替换已加载bean_spring_03

定义xml配置文件:

spring配置bean之前替换配置属性 spring替换已加载bean_xml_04

定义测试类:

public class TestMain {
	public static void main(String args[]){
		ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		Zoo zoo = (Zoo) context.getBean("zoo");
		System.out.println(zoo.toString());
	}
}

测试结果:

spring配置bean之前替换配置属性 spring替换已加载bean_spring_05

如果将xml配置文件内的default-autowire="byName"去掉,则bean失效,因为spring不知道按什么规则匹配bean到具体的class。

autowire有两处点:

  • 可以配置在根标签下,表示对全局起作用,属性名为default-autowire
  • 可以配置在标签下,表示对当前起作用,属性名为autowire

通常都是在根标签下配置自动装配比较多,default-autowire有四种取值:

  • no:默认,即不进行自动装配,每一个对象的注入比如依赖一个标签
  • byName:按照beanName进行自动装配,使用setter注入
  • byType:按照bean类型进行自动装配,使用setter注入
  • constructor:与byType差不多,不过最终属性通过构造函数进行注入

二、使用@Autowired去掉property

xml配置文件更改为;

spring配置bean之前替换配置属性 spring替换已加载bean_spring_06

Zoo改为:

spring配置bean之前替换配置属性 spring替换已加载bean_xml_07

运行后依然正常得到数据。
这里有一点需要注意,Zoo.java内删除了set方法是因为:“之前是因为property标签需要用到set方法,而现在不使用property标签了”。
有一个细节性的问题是,假如bean里面有两个property(也就是xml文件内的两个property标签不删除),Zoo.java里面又去掉了属性的getter/setter并使用@Autowired注解标注这两个属性那会怎么样?答案是Spring会按照xml优先的原则去Zoo.java中寻找这两个属性的getter/setter,导致的结果就是初始化bean报错。

这里@Autowired注解的意思就是,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。

三、如果此时再将xml文件内的后两个bean标签去掉

spring配置bean之前替换配置属性 spring替换已加载bean_spring_08

如果再运行,会抛出异常:

九月 15, 2021 11:41:28 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo': Unsatisfied dependency expressed through field 'tiger'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.wen.ssm.domain.Tiger' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo': Unsatisfied dependency expressed through field 'tiger'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.wen.ssm.domain.Tiger' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
	at com.wen.ssm.test.TestMain.main(TestMain.java:9)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.wen.ssm.domain.Tiger' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
	... 15 more

Process finished with exit code 1

解决方法:

因为,@Autowired注解要去寻找的是一个Bean,Tiger和Monkey的Bean定义都给去掉了,自然就不是一个Bean了,Spring容器找不到也很好理解。那么,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?可以的,其实异常信息里面也给出了提示了,就是将@Autowired注解的required属性设置为false即可:

spring配置bean之前替换配置属性 spring替换已加载bean_xml_09

使用@Resource同样可以达到去掉property标签的效果

Zoo.xml代码改为:

spring配置bean之前替换配置属性 spring替换已加载bean_spring_10


运行结果不变。

这是详细一些的用法,说一下@Resource的装配顺序:
1、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
2、指定了name或者type则根据指定的类型去匹配bean
3、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错

然后,区分一下@Autowired和@Resource两个注解的区别
1、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
2、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了;
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

四、使用@Component去掉bean标签

spring配置bean之前替换配置属性 spring替换已加载bean_java_11

spring配置bean之前替换配置属性 spring替换已加载bean_xml_12

spring配置bean之前替换配置属性 spring替换已加载bean_spring_13

spring配置bean之前替换配置属性 spring替换已加载bean_spring_14

@Component: 标注Spring管理的Bean,使用@Component注解在一个类上,表示将此类标记为Spring容器中的一个Bean。

五、使用@ComponentScan去掉context:component-scan标签

测试类代码更改为:

@ComponentScan(basePackages = {"com.wen.ssm.domain"})
public class TestMain {
	public static void main(String args[]){
		//ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		//Zoo zoo = (Zoo) context.getBean("zoo");
		ApplicationContext context = new AnnotationConfigApplicationContext(TestMain.class);
		Zoo zoo = (Zoo) context.getBean(Zoo.class);
		System.out.println(zoo.toString());
	}
}

Spring中@ComponentScan的使用规则