如果要在“应用启动前”使用 Solon Bean，还需要了解[《Bean 生命周期》](/article/448)的关键生命节点：

| 节点 | 说明 | 
| -------- | -------- | 
| 1. ::new()     | 构造     | 
| 2. @Inject(注入)     | 基于订阅，不确定具体依赖什么时候会被注入     | 
|  | ::登记到容器；并发布通知；订阅它的注入会被执行 |
| 4. start()   | 容器扫描完成后执行（即在 AppContext::start 函数内执行）     | 
| 5. stop()   | 容器停止时执行（即 AppContext::stop） | 


### 1、如何注入Bean？

* Bean 注入到字段（但，不支持属性方法注入）

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

@Component
public class DemoService {
    //通过bean type注入（注入是异步的，不能在构造函数里使用）
    @Inject
    private static TrackService trackService; //v3.0 后，支持静态字段注入
    
    //通过bean name注入
    @Inject("userService")
    private UserService userService;
}
```

* Bean 注入到构造参数（即，构造函数注入）

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

@Component
public class DemoService {
    private final TrackService trackService;
    private final UserService userService;
    
    public DemoService(TrackService trackService, @Inject("userService") UserService userService) {
        this.trackService = trackService;
        this.userService = userService;
    }
}
```

* 注入到 `@Bean` 函数的参数（以参数注入，具有依赖约束性）。引用已有 Bean 构建新的 Bean：

```java
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.data.dynamicds.DynamicDataSource;

@Configuration
public class DemoConfig{
    @Bean("ds3") 
    public DataSource ds(@Inject("ds1") DataSource ds1, @Inject("ds2") DataSource ds2){
        //构建一个动态数据源
        DynamicDataSource tmp = new DynamicDataSource();
        
        tmp.setStrict(true);
        tmp.addTargetDataSource("ds1", ds1);
        tmp.addTargetDataSource("ds2", ds2);
        tmp.setDefaultTargetDataSource(ds1);
        
        return tmp;
    }
}
```


### 2、如何手动获取Bean？

* 同步获取（要注意时机）

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

public class DemoService{
    private TrackService trackService;
    private UserService userService;
    
    public DemoService(){
        //同步方式，根据bean type获取Bean（如果此时不存在，则返回null。需要注意时机）
        trackService = Solon.context().getBean(TrackService.class);
        
        //同步方式，根据bean type获取Bean（如果此时不存在，自动生成一个Bean并注册+返回）
        trackService = Solon.context().getBeanOrNew(TrackService.class);
       
        //同步方式，根据bean name获取Bean（如果此时不存在，则返回null）
        userService = Solon.context().getBean("userService");
    }
}
```

* 异步获取（如果存在，会直接回调；如果没有，目标产生时会通知回调） //以静态字段为例

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

public class DemoService{
    private static TrackService trackService;
    private static  UserService userService;
    
    static{
        //异步订阅方式，根据bean type获取Bean（已存在或产生时，会通知回调；否则，一直不回调）
        Solon.context().getBeanAsync(TrackService.class, bean-> {
            trackService = bean;
            
            //bean 获取后，可以做些后续处理。。。
        });
        
        //异步订阅方式，根据bean name获取Bean
        Solon.context().getBeanAsync("userService", bean-> {
            userService = bean;
        });
    }
}
```

有时候不方便扫描，或者不必扫描，那手动模式就是很大的一种自由。

### 3、如何获取一批相同基类的Bean 集合？

方式有很多，大家按需选择。或许用订阅接口实时获取，是个不错的选择。

* 通过注入（相当于下面的“通过生命周期获取”。<mark>注入时机较晚在扫描完成后才注入！</mark>）

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

@Component
public class DemoService{
    @Inject
    private List<EventService> eventServices;
    
    @Inject
    private Map<String, EventService> eventServiceMap;
}

@Configuration
public class DemoConfig{
    @Bean
    public void demo1(@Inject List<EventService> eventServices){ }
    
    @Bean
    public void demo2(@Inject Map<String, EventService> eventServiceMap){ }
}
```

* 通过订阅接口（可实时获取）

```java
context.subBeansOfType(DataSource.class, bean->{
    //获取所有 DataSource Bean
    //一般由：@Component 产生 或者 @Configuration + @Bean 产生
});

context.subWrapsOfType(DataSource.class, bw->{
    // bw.name() 获取 bean name 
    // bw.get() 获取 bean
    //一般由：@Component 产生 或者 @Configuration + @Bean 产生
});
```

* 通过生命周期获取

```java
context.lifecycle(() -> {
    List<DataSource> beans = context.getBeansOfType(DataSource.class);
    List<BeanWrap>   wraps = context.getWrapsOfType(DataSource.class);
    
    Map<String, DataSource>  beansMap = context.getBeansMapOfType(DataSource.class);
});

```

* 通过生命周期，直接遍历已注册的 Bean（即 AppContext::start 事件）

```java
//手动添加 lifecycle 进行遍历，确保所有 Bean 已处理完成

//a. 获取 name "share:" 开头的 bean  //context:AppContext
context.lifecycle(() -> {
    context.beanForeach((k, v) -> {
        if (k.startsWith("share:")) {
            render.putVariable(k.split(":")[1], v.raw());
        }
    });
});

//b. 获取 IJob 类型的 bean  //context:AppContext
context.lifecycle(() -> {
    context.beanForeach((v) -> {
        if (v.raw() instanceof IJob) {
            JobManager.register(new JobEntity(v.name(), v.raw()));
        }
    });
});
```

### 4、获取 `Map<String, Bean>` 集合的条件说明

注入或手动获取 `Map<String, Bean>`，要求相关的 Bean 必须有名字。即使用 `@Component` 或 `@Bean` 或手动注册时，要有名字。

一般用不到名字的，可改用 `List<Bean>` 获取 Bean 集合。

