@Autowired //通过setter方法实现注入
public void setWolf3Bean(Wolf3Bean wolf3Bean) {
this.wolf3Bean = wolf3Bean;
}
}
构造器注入
当两个类属于强关联时,我们也可以通过构造器的方式来实现注入:
@Service
public class UserService {
private Wolf2Bean wolf2Bean;
@Autowired //通过构造器注入
public UserService(Wolf2Bean wolf2Bean) {
this.wolf2Bean = wolf2Bean;
}
}
接口注入
在上面的三种常规注入方式中,假如我们想要注入一个接口,而当前接口又有多个实现类,那么这时候就会报错,因为 Spring
无法知道到底应该注入哪一个实现类。比如我们上面的三个类全部实现同一个接口 IWolf
,那么这时候直接使用常规的,不带任何注解元数据的注入方式来注入接口 IWolf
。
@Autowired
private IWolf iWolf;
此时启动服务就会报错:
这个就是说本来应该注入一个类,但是 Spring
找到了三个,所以没法确认到底应该用哪一个。这个问题如何解决呢?
解决思路主要有以下 5
种:
通过配置文件和 @ConditionalOnProperty 注解实现
通过 @ConditionalOnProperty
注解可以结合配置文件来实现唯一注入。下面示例就是说如果配置文件中配置了 lonely.wolf=test1
,那么就会将 Wolf1Bean
初始化到容器,此时因为其他实现类不满足条件,所以不会被初始化到 IOC
容器,所以就可以正常注入接口:
@Component
@ConditionalOnProperty(name = “lonely.wolf”,havingValue = “test1”)
public class Wolf1Bean implements IWolf{
}
当然,这种配置方式,编译器可能还是会提示有多个 Bean
,但是只要我们确保每个实现类的条件不一致,就可以正常使用。
通过其他 @Condition 条件注解
除了上面的配置文件条件,还可以通过其他类似的条件注解,如:
-
@ConditionalOnBean:当存在某一个
Bean
时,初始化此类到容器。 -
@ConditionalOnClass:当存在某一个类时,初始化此类的容器。
-
@ConditionalOnMissingBean:当不存在某一个
Bean
时,初始化此类到容器。 -
@ConditionalOnMissingClass:当不存在某一个类时,初始化此类到容器。
-
…
类似这种实现方式也可以非常灵活的实现动态化配置。
不过上面介绍的这些方法似乎每次都只能固定注入一个实现类,那么如果我们就是想多个类同时注入,不同的场景可以动态切换而又不需要重启或者修改配置文件,又该如何实现呢?
通过 @Resource 注解动态获取
如果不想手动获取,我们也可以通过 @Resource
注解的形式动态指定 BeanName
来获取:
@Component
public class InterfaceInject {
@Resource(name = “wolf1Bean”)
private IWolf iWolf;
}
如上所示则只会注入 BeanName
为 wolf1Bean
的实现类。
通过集合注入
除了指定 Bean
的方式注入,我们也可以通过集合的方式一次性注入接口的所有实现类:
@Component
public class InterfaceInject {
@Autowired
List list;
@Autowired
private Map<String,IWolf> map;
}
上面的两种形式都会将 IWolf
中所有的实现类注入集合中。如果使用的是 List
集合,那么我们可以取出来再通过 instanceof
关键字来判定类型;而通过 Map
集合注入的话,Spring
会将 Bean
的名称(默认类名首字母小写)作为 key
来存储,这样我们就可以在需要的时候动态获取自己想要的实现类。
@Primary 注解实现默认注入
除了上面的几种方式,我们还可以在其中某一个实现类上加上 @Primary
注解来表示当有多个 Bean
满足条件时,优先注入当前带有 @Primary
注解的 Bean
:
@Component
@Primary
public class Wolf1Bean implements IWolf{
}
通过这种方式,Spring
就会默认注入 wolf1Bean
,而同时我们仍然可以通过上下文手动获取其他实现类,因为其他实现类也存在容器中。
手动获取 Bean 的几种方式
在 Spring
项目中,手动获取 Bean
需要通过 ApplicationContext
对象,这时候可以通过以下 5
种方式进行获取:
直接注入
最简单的一种方法就是通过直接注入的方式获取 ApplicationContext
对象,然后就可以通过 ApplicationContext
对象获取 Bean
:
@Component
public class InterfaceInject {
@Autowired
private ApplicationContext applicationContext;//注入
public Object getBean(){
return applicationContext.getBean(“wolf1Bean”);//获取bean
}
}
通过 ApplicationContextAware 接口获取
通过实现 ApplicationContextAware
接口来获取 ApplicationContext
对象,从而获取 Bean
。需要注意的是,实现 ApplicationContextAware
接口的类也需要加上注解,以便交给 Spring
统一管理(这种方式也是项目中使用比较多的一种方式):
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
- 通过名称获取bean
*/
public static T getBeanByName(String beanName){
return (T) applicationContext.getBean(beanName);
}
/**
- 通过类型获取bean
*/
public static T getBeanByType(Class clazz){
return (T) applicationContext.getBean(clazz);
}
}
封装之后,我们就可以直接调用对应的方法获取 Bean
了:
Wolf2Bean wolf2Bean = SpringContextUtil.getBeanByName(“wolf2Bean”);
Wolf3Bean wolf3Bean = SpringContextUtil.getBeanByType(Wolf3Bean.class);
通过 ApplicationObjectSupport 和 WebApplicationObjectSupport 获取
这两个对象中,WebApplicationObjectSupport
继承了 ApplicationObjectSupport
,所以并无实质的区别。
同样的,下面这个工具类也需要增加注解,以便交由 Spring
进行统一管理:
@Component
public class SpringUtil extends /WebApplicationObjectSupport/ ApplicationObjectSupport {
private static ApplicationContext applicationContext = null;
public static T getBean(String beanName){
return (T) applicationContext.getBean(beanName);
}
@PostConstruct
public void init(){
applicationContext = super.getApplicationContext();
}
}
有了工具类,在方法中就可以直接调用了:
@RestController
@RequestMapping(“/hello”)
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
总结
本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!
MySQL50道高频面试题整理:
995)]
[外链图片转存中…(img-w6yHvzo3-1710424920996)]
[外链图片转存中…(img-C1SqFhc8-1710424920996)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-ItZEUN0M-1710424920996)]
总结
本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!
MySQL50道高频面试题整理:
[外链图片转存中…(img-8vAKVpdg-1710424920997)]