二、构建一个 Bean 的三种方式(IOC)
关于 Solon Bean 有两个重要的概念:名字,类型。对应的是:
- 按名字注册,则按名字注入、按名字获取、按名字检测
- 按类型注册,则按类型注入、按类型获取、按类型检测(相同类型只注册一个;除非名字不同)
类型注册在自动装配时,也会同时注册 “申明类型” 与 “实例类型” 的一级实现接口类型。
1、手动(一般,在开发插件时用)
简单的构建:
//生成普通的Bean(只是注册,不会做别的处理;身上的注解会被乎略掉)
Solon.context().wrapAndPut(UserService.class, new UserServiceImpl());
//生成Bean,并触发身上的注解处理(比如类上有 @Controller 注解;则会执行 @Controller 对应的处理)
Solon.context().beanMake(UserServiceImpl.class);
更复杂的手动,以适应特殊的需求:
UserService bean = new UserServiceImpl();
//可以进行手动字段注入
Solon.context().beanInject(bean);
//可以再设置特殊的字段
bean.setXxx("xxx");
//包装Bean(指定名字的)
BeanWrap beanWrap = Solon.context().wrap("userService", bean);
//包装Bean(指定类型的)
//BeanWrap beanWrap = Solon.context().wrap(UserService.class, bean);
//以名字注册
Solon.context().putWrap("userService", beanWrap);
//以类型注册
Solon.context().putWrap(UserService.class, beanWrap);
下面2种模式,必须要被扫描到。在不便扫描,或不须扫描时手动会带来一种自由感。
2、用配置器类
本质是 @Configuration + @Bean 的组合,并且 Config 要被扫描到
@Configuration
public class Config{
//以类型进行注册(默认) //可用 @Inject(UserService.class) 注入
@Bean
public UserService build(){
return new UserServiceImpl();
}
//以名字进行注册 //可用 @Inject("userService") 注入
@Bean("userService")
public UserService build2(){
return new UserServiceImpl();
}
//同时以名字和类型进行注册 //支持类型或名字注入
@Bean(name="userService", typed=true)
public UserService build3(){
return new UserServiceImpl();
}
}
使用带条件的构建
@Configuration
public class Config{
//注解条件控制 (应对简单情况)
@Bean
@Condition(onProperty="${cache.enable} = true")
public CacheService cacheInit(@Inject("${cache.config}") CacheServiceSupplier supper){
return supper.get();
}
//手动条件控制 Bean 产生(应对复杂点的情况)
@Bean
public CacheService(@Inject("${cache.type}") int type){
if (type == 1){
return Solon.cfg().getBean("cache.config", MemCacheService.class);
} else if (type == 2){
return Solon.cfg().getBean("cache.config", RedisCacheService.class);
} else if (type == 3){
return Solon.cfg().getBean("cache.config", JdbcCacheService.class);
} else{
return new LocalCacheService();
}
}
}
顺带,还可以借用 @Configuration + @Bean 的组合,进行初始化
@Configuration
public class Config{
@Bean
public void titleInit(@Inject("${demo.title}") String title){
Config.TITLE = title;
}
@Bean
public void dsInit(@Inject("${demo.ds}") String ds) {
String[] dsNames = ds.split(",");
for (String dsName : dsNames) {
Props props = Solon.cfg().getProp("demo.db-" + dsName);
if (props.size() > 0) {
//按需创建数据源
DataSource db1 = props.getBean("", HikariDataSource.class);
//手动推到容器内
BeanWrap bw = Solon.context().wrap(DataSource.class, db1);
Solon.context().putWrap(dsName, bw);
}
}
}
}
3、使用组件注解(必须要能被扫描到)
a. 以类型进行注册(默认)
//@Singleton(false) //默认都是单例,如果非例单加上这个注解
@Component
public class UserServiceImpl implements UserService{
}
//通过 @Inject(UserService.class) 注入
//通过 Solon.context().getBean(UserService.class) 手动获取 //要确保组件已注册
b. 以名字进行注册
@Component("userService")
public class UserServiceImpl implements UserService {
}
//通过 @Inject("userService") 注入
//通过 Solon.context().getBean("userService") 手动获取 //要确保组件已注册
c. 以名字和类型同时进行注册
@Component(name="userService", typed=true)
public class UserServiceImpl implements UserService{
}
//通过 @Inject("userService") 注入
//通过 Solon.context().getBean("userService") 手动获取 //要确保组件已注册
//通过 @Inject(UserService.class) 注入
//通过 Solon.context().getBean(UserService.class) 手动获取 //要确保组件已注册
四、@Bean
和 @Component
注解主要区别
@Component | @Bean | |
---|---|---|
装配方式 | 自动装配 | 手动装配 |
作用范围 | 注解在类上 | 注解在 @Configuration 类的 public 方法上 |
单例控制 | 可以申明自己是不是单例 | 只能是单例 |
类型注册 | 以实例类型进行注册 (同时会注册,一级父接口类型) | 同时注册返回的 申明类型 和 实例类型 (以及注册,它们的一级父接口类型) |
- 类型注册之
@Component
说明:
class AbsUserService implements UserService { }
@Component
class UserServiceImpl1 extends AbsUserService { }
@Component
class UserServiceImpl2 extends AbsUserService implements UserService { }
UserServiceImpl1 注册时,只注册 UserServiceImpl1 类型;
UserServiceImpl2 注册时。会注册 UserServiceImpl2 和 UserService 类型;
- 类型注册之
@Bean
说明:
interface UserService extends IService { }
class AbsUserService implements UserService { }
class UserServiceImpl extends AbsUserService implements UserService { }
@Configuration
public class Config{
@Bean
public UserServiceImpl case1(){
return new UserServiceImpl();
}
@Bean
public UserService case2(){
return new UserServiceImpl();
}
}
case1 会注册 UserServiceImpl 和 UserService 类型;
case2 会注册 UserServiceImpl、UserService、IService;
5、补充说明
通过 getBeansMapOfType 接口,获取 Bean map 集合时。需要给托管的 Bean 取名字!
@Component(name="case1", typed=true) //同时,按名字 和 类型注册
class UserServiceImpl2 extends AbsUserService { }
@Component(name="case2", typed=true)
class UserServiceImpl2 extends AbsUserService implements UserService { }
//获取 bean map 集合
Map<String,UserService.class> userServiceMap = Solon.context().getBeansMapOfType(UserService.class)
//注入 bean map 集合
@Inject
Map<String,UserService.class> userServiceMap;