Solon v3.0.3

二、构建一个 Bean 的三种方式(IOC)

</> markdown

关于 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;