在前面章节我们已有进行模拟Spring框架之实作范例及介绍,使用者可理解到所有服务透过一项框架套件代理的过程,故本章节将提供使用者一些基本设置的套件,提供开发者了解Spring框架之控制反转(IoC,Inverse of Control)与依赖注入(DI,Dependency Injection)两项核心概念,运用此范例配置可提供给所有读者当各类元件测试的基底,且读者可快速学习到建立一套基础的Spring Boot Starter服务架构需要运用到哪些套件与开发流程,而为什麽要选用Spring Boot Starter呢?因此套件的规范与设定优於Spring周遭套件,也整合许多外挂套件观念,只需寻找spring-boot-starter-* 字母开头套件当外挂,运用起来相当简单,故在此推荐给众多读者做范例使用 !
implementation ('org.springframework.boot:spring-boot-starter')
implementation ('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-jetty')
compile('org.springframework.boot:spring-boot-starter-aop')
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.7'
//unit test
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.springframework', name: 'spring-test'
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version : '1.3'
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
本篇全部将以注解(Annotation)进行各种Bean的配置,故我们先产生一个基本的模型(Model named: Chef),透过AppConfig元件进行建立两项Bean类别元件,当我们服务启动的时候,会自动将Bean载入Spring IoC容器中,故我们亦可透过ApplicationContext方式取得Bean类别,亦可透过注解方式(@Autowired)获取Bean类别,详细范例如下请参照。
public static void main(String[] args) {
SpringApplication.run(ApplicationBoot.class,args);
}
Map<String,Object> beansContainer = null;
@PostConstruct
public void init() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
beansContainer = ctx.getBeansWithAnnotation(Bean.class);
}
@Override
public String getNameByChef(String name) {
return ((Chef)beansContainer.get(name)).getName();
}
main.java.sw.sample.spring.service.ConfigServiceImpl.java
@Primary
@Bean(name= "chef-B")
public Chef initChefB() {
Chef chef = new Chef();
long generatedLong = 500000L + (long) (Math.random() * (1000000L - 500000L));
chef.setId(generatedLong);
chef.setName("Jyuh");
chef.setRemark("Michelin-chef and dessert");
List<String> specialSkills = new ArrayList<String>();
specialSkills.add("Gold cake");
specialSkills.add("noodle pie");
specialSkills.add("chocolate pie");
chef.setSpecialSkills(specialSkills);
return chef;
}
test.java.sw.sample.spring.ConfigServiceSuite.java
@Autowired
Chef chef;
@Test
public void validateChefBRemark() {
assertTrue(chef.getRemark().equalsIgnoreCase("Michelin-chef and dessert"));
System.out.println("validate Chef B Remark success!");
}
透过以上程序码区段叙述获取Bean类别元件,便可进行各类程序逻辑运用与判断。
在软件开发周期定义上,无论何种元件都会有一个生命周期,以下是注入一个Bean的流程架构,Spring 会先取出相关属性值,如:需注册多个相同类别的Bean,将在每个Bean内建入不相同的变量参数,此时就会去对应不同的识别名称去注册Bean,此时会产生将配置给Bean的对映名称,接下来进行确认此类别是否有配置初始化方法,若有会产生相关预设好的Bean,在进行触发此方法进行初始化参数配置,最後将检查是否有配置Destroy的方法,当进行系统关闭,每个Bean移除前都会触发此方法,当配置完後会将此Bean存入BeanFactory变量池中,并将预设好的名称作为索引值,以提供使用者随时可呼叫配置使用。
图一 Bean 生命周期
从此架构可以看出我们在范例中可以一次注册多个Bean,每个Bean都可以连接@PostConstruct及@PreDestroy两项方法,开发者可透过每个Bean的识别名称进行获取该元件类别,如何注册多个Bean[chef-A、chef-B],请看下面代码:
已注解方式注册Bean
@Configuration
public class AppConfig {
@Bean(name= "chef-A")
public Chef initChefA() {
Chef chef = new Chef();
long generatedLong = 500000L + (long) (Math.random() * (1000000L - 500000L));
chef.setId(generatedLong);
chef.setName("Weisting");
chef.setRemark("Michelin-chef and main meal chef.");
List<String> specialSkills = new ArrayList<String>();
specialSkills.add("Gold chicken");
specialSkills.add("Assorted fried noodles");
specialSkills.add("Crab Fragrant Huangbao");
chef.setSpecialSkills(specialSkills);
return chef;
}
@Primary
@Bean(name= "chef-B")
public Chef initChefB() {
Chef chef = new Chef();
long generatedLong = 500000L + (long) (Math.random() * (1000000L - 500000L));
chef.setId(generatedLong);
chef.setName("Jyuh");
chef.setRemark("Michelin-chef and dessert");
List<String> specialSkills = new ArrayList<String>();
specialSkills.add("Gold cake");
specialSkills.add("noodle pie");
specialSkills.add("chocolate pie");
chef.setSpecialSkills(specialSkills);
return chef;
}
}
获取Chef Bean 方法如下
public class ConfigServiceSuite extends ServiceTestBase {
@Autowired
ConfigService configService;
@Autowired
Chef chef;
@Test
public void validateChefBRemark() {
assertTrue(chef.getRemark().equalsIgnoreCase("Michelin-chef and dessert"));
System.out.println("validate Chef B Remark success!");
}
@Test
public void validateChefBName() {
assertTrue(chef.getName().equalsIgnoreCase("Jyuh"));
System.out.println("validate Chef B Remark success!");
}
...
}
public void validateChefBRemark() {
assertTrue(chef.getRemark().equalsIgnoreCase("Michelin-chef and dessert"));
System.out.println("validate Chef B Remark success!");
}
@Test
public void validateChefBName() {
assertTrue(chef.getName().equalsIgnoreCase("Jyuh"));
System.out.println("validate Chef B Remark success!");
}
Run test task
gradle test
Run open result html
open ./build/reports/tests/test/classes/sw.sample.spring.ConfigServiceSuite.html
Spring boot starter base sample code
Spring 容器中Bean生命周期之@PostConstruct和@PreDestroy注解
23.14 Using the @PostConstruct and @PreDestroy Annotations with CDI Managed Bean Classes
<<: Day05 X Code Minimize & Uglify
今天先来看一段MuleSoft公司介绍API的影片吧! 从影片中我们能够很清楚的知道API其实就是扮...
流程 开发本机将新的commit push到bitbucket bitbucket的指定专案变动,透...
从地端 On-Premise的传统资讯部署,再到云端 Cloud的新形态部署模式,在这个转型过程初...
我们可以在变数做宣告时,是否绑定型别来判定程序语言是动态型别或是静态型别,而两者区别如下: 动态型别...
快来探索AI的世界 Day 2 学习目标 人工智慧的演进 人工智慧的分级 机器是如何学习的 人工智慧...