关于 Solon Bean 有两个重要的概念：名字，类型。对应的是：

* 按名字注册，则按名字注入、按名字获取、按名字检测
* 按类型注册，则按类型注入、按类型获取、按类型检测（相同类型只注册一个；除非名字不同）

类型注册在自动装配时，也会同时注册 “声明类型” 与 “实例类型” 的一级实现接口类型。

### 1、手动（一般，在开发插件时用）

简单的构建：

```java
import org.noear.solon.Solon;

//生成普通的Bean（只是注册，不会做别的处理；身上的注解会被乎略掉）
Solon.context().wrapAndPut(UserService.class, new UserServiceImpl());

//生成Bean，并触发身上的注解处理（比如类上有 @Controller 注解；则会执行 @Controller 对应的处理）
Solon.context().beanMake(UserServiceImpl.class);
```

更复杂的手动，以适应特殊的需求：

```java
import org.noear.solon.Solon;
import org.noear.solon.core.BeanWrap;

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 要被扫描到

```java
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;

@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();
    }
}
```

使用带条件的构建

```java
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.data.cache.CacheService;
import org.noear.solon.data.cache.CacheServiceSupplier;
import org.noear.solon.data.cache.LocalCacheService;

@Configuration
public class Config{
    //注解条件控制 （应对简单情况）
    @Bean
    @Condition(onExpression="${cache.enable:false} == 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 的组合，进行初始化

```java
import org.noear.solon.Solon;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.BeanWrap;
import org.noear.solon.core.Props;

@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. 以类型进行注册（默认）

```java
import org.noear.solon.annotation.Component;

//@Singleton(false) //默认都是单例，如果非例单加上这个注解
@Component
public class UserServiceImpl implements UserService{

}

//通过 @Inject(UserService.class) 注入
//通过 Solon.context().getBean(UserService.class) 手动获取 //要确保组件已注册
```

b. 以名字进行注册

```java
import org.noear.solon.annotation.Component;

@Component("userService")
public class UserServiceImpl implements UserService {

}

//通过 @Inject("userService") 注入
//通过 Solon.context().getBean("userService") 手动获取 //要确保组件已注册
```


c. 以名字和类型同时进行注册

```java
import org.noear.solon.annotation.Component;

@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 方法上     |
| 单例控制     | 可以声明自己是不是单例     | 只能是单例     |
| 类型注册     | 以实例类型进行注册<br/>（同时会注册，一级父接口类型）     | 同时注册返回的 声明类型 和 实例类型<br/>（以及注册，它们的一级父接口类型）     |

* 类型注册之 `@Component` 说明：

```java
import org.noear.solon.annotation.Component;

class AbsUserService implements UserService { }

@Component
class UserServiceImpl1 extends AbsUserService { }

@Component
class UserServiceImpl2 extends AbsUserService implements UserService { }
```

UserServiceImpl1 注册时，只注册 UserServiceImpl1 类型；

UserServiceImpl2 注册时。会注册 UserServiceImpl2 和 UserService 类型；

* 类型注册之 `@Bean` 说明：

```java
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;

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 取名字！

```java
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

@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;
```
