Spring加载bean版本迭代
一、xml时代
先定义两个动物类:
创建一个动物园类:
定义xml配置文件:
定义测试类:
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());
}
}
测试结果:
如果将xml配置文件内的default-autowire="byName"去掉,则bean失效,因为spring不知道按什么规则匹配bean到具体的class。
autowire有两处点:
- 可以配置在
根标签下,表示对全局 起作用,属性名为default-autowire - 可以配置在
标签下,表示对当前 起作用,属性名为autowire
通常都是在
- no:默认,即不进行自动装配,每一个对象的注入比如依赖一个
标签 - byName:按照beanName进行自动装配,使用setter注入
- byType:按照bean类型进行自动装配,使用setter注入
- constructor:与byType差不多,不过最终属性通过构造函数进行注入
二、使用@Autowired去掉property
xml配置文件更改为;
Zoo改为:
运行后依然正常得到数据。
这里有一点需要注意,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标签去掉
如果再运行,会抛出异常:
九月 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即可:
使用@Resource同样可以达到去掉property标签的效果
Zoo.xml代码改为:
运行结果不变。
这是详细一些的用法,说一下@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标签
@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());
}
}