自动装配:Spring利用依赖注入,完成对IOC容器中的各个组件的依赖关系赋值
1.@Autowired
1)、默认优先按照类型去容器中找对应的组件---->ioc.getBean(BookDao.class);,如果找到了就赋值
2)、如果找到了多个相同类型的组件,再讲属性的名称作为组件的id去查找--->ioc.getBean("bookDao");
3)、使用@Qualifier("bookDao")来明确指定需要装配的组件的id,而不是使用属性名作为id
4)、自动装配默认的是一定要在容器中找到组件,如果容器中没有就会报错
可以设置required = false,是其不必须在容器中找到组件,找不到就是null
@Autowired(required = false)
5)、容器中有多个相同类型的组件,还可以使用@Primary设置每次装配首选的是这个bean,和@Qualifier一起使用 ,还是会自动装配@Qualifier明确指定的bean
给BookService自动注入BookDao
@Service public class BookService { @Qualifier("bookDao") @Autowired private BookDao bookDao; public BookDao getBookDao() { return bookDao; } public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
测试结果:
BookService里的BookDao自动装配成功
2.Spring还支持@Resource(JSR250)和@Inject(JSR330),java规范的注解
1.@Resource:可以和@Autowired一样实现自动装配功能,没有@Primary,也没有required属性
2.@Inject:使用需要导入javax.inject包,和@Autowired一样实现自动装配功能,支持@Primary,没有required属性
3.@Autowired的其他用法
@Autowired:不仅可以也在属性上,还能标注在方法上、构造器上、参数上
①、标注在方法上测试
@Bean+方法参数:参数从容器中获取(@Autowired 可以省略)
@Bean public Boss boss(@Autowired Car car){ return new Boss(); }
在setCar方法上标注@Autowired:
@Component public class Boss { private Car car; public Car getCar() { return car; } /* * 将Autowired标注在方法上 * Spring容器创建对象就会调用这个方法完成赋值 * 方法使用的自定义的值从ioc容器中获取 * */ @Autowired public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Boss{" + "car=" + car + '}'; } }
测试结果:
②、构造器
默认加在容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值
如果组件只有一个有参构造器,那么有参构造器的Autowired可以省略
@Autowired标注在Boss的有参构造器上:
@Component public class Boss { private Car car; //构造器要用的组件都是从ioc容器中获取 @Autowired public Boss(Car car) { this.car = car; System.out.println("Boss的有参构造器。。。。"); } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Boss{" + "car=" + car + '}'; } }
测试结果:
③、参数上
标注在参数上效果一样,不多测试
4.自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,.....)
自定义组件实现xxxAware接口:在创建对象的时候,会调用接口规定的方法注入相关组件
例子:实现了ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware三个Aware接口
@Component public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware { private ApplicationContext applicationContext; //获取ioc容器 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; System.out.println("传入的IOC: "+applicationContext); } //获取bean名字 public void setBeanName(String name) { System.out.println("当前Bean的名字: "+name); } // public void setEmbeddedValueResolver(StringValueResolver resolver) { String s = resolver.resolveStringValue("你好${os.name} 我是#{2*4}"); System.out.println("解析的字符串:"+s); } }
在容器创建Red对象时调用Aware的方法
结果:
Aware的原理
Debug运行:
查看方法调用栈的信息:
先调用了postProcessBeforeInitialization(final Object bean, String beanName)方法,
在方法里调用了
invokeAwareInterfaces方法:
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
判断当前的bean是否实现了这些接口,如果实现了就调用该接口的方法 ,传入组件