我们说 Spring Boot 是 Spring 框架对“约定优先于配置(Convention Over Configuration)”理念的最佳实践产物,一个典型的Spring Boot 应用本质上其实就是一个基于 Spring 框架的应用。
本篇,将学习Spring 框架中较为经典的依赖注入和Java配置知识,并通过实践样例对知识点进行加强,以更好的理解 Spring Boot 的精髓。
一、依赖注入
Spring框架比较经典是控制反转(Inversion of Control-IOC)和依赖注入(dependency injection-DI),在Spring环境下是等同的概念。依赖注入的主要目的是为了解耦,体现了一种“组合”的理念。
Spring IoC容器(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。Spring提供使用xml、注解、Java配置、Groovy配置实现Bean的创建和注入。无论是xml配置、注解配置还是Java配置,都被称为配置元数据,所谓元数据即描述数据的数据。元数据本身不具备任何可执行的能力,只能通过外界代码来对这些元数据行解析后进行一些有意义的操作。Spring容器解析这些配置元数据进行Bean初始化、配置和管理依赖。
声明Bean的注解:
* -@Component 组件,没有明确的角色。
* -@Service 在业务逻辑层(Service层)使用。
* -@Repository 在数据访问层(dao 层)使用。
* -@Controller 在展现层(MVC->Spring MVC)使用。
注入Bean的注解,一般情况下是通用的。
*-@Autowired 是Spring提供的注解。
*-@Inject 是JSR-330提供的注解。
*-@Resource 是JSR-250提供的注解。
@Autowired 、@Inject 、@Resource 可注解在set方法上或者属性上,一般建议注解在属性上,这样代码更少、层次更清晰。
下面将通过样例展示基于注解的Bean的初始化和依赖注入。
创建一个名称为AnnotationConfiguration的Maven工程,pom.xml 如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.freesky</groupId>
<artifactId>AnnotationConfiguration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>AnnotationConfiguration</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 添加Java版本 -->
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 添加spring framework 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
</project>
编写功能类:
package com.freesky.AnnotationConfiguration;
import org.springframework.stereotype.Service;
/**
* FunctionService
*
* @see
* 使用@Service注解声明当前FunctionService类是Spring管理的一个Bean。
* 其中,使用@Component、@Service、@Reposigory和@Controller是等效的,可以根据需要选用。
*
* @see
* 声明Bean的注解:
* -@Component 组件,没有明确的角色。
* -@Service 在业务逻辑层(Service层)使用。
* -@Repository 在数据访问层(dao 层)使用。
* -@Controller 在展现层(MVC->Spring MVC)使用。
*/
@Service
public class FunctionService {
public String sayHello(String word) {
return "Hello " + word + " !";
}
}
编写功能类的使用类
package com.freesky.AnnotationConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 功能类的使用类
*
*
* 使用@Service注解声明当前UseFunctionService类是Spring管理的一个Bean。
* 使用@Autowired将UseFunctionService的实体Bean注入到UseFunctionService中,让UseFunctionService具备FunctionService的功能。
* 此处使用@Inject和@Resource注解是等效的。
*
*/
@Service
public class UseFunctionService {
@Autowired
FunctionService functionService;
public String sayHello(String word) {
return functionService.sayHello(word);
}
}
编写配置类
package com.freesky.AnnotationConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 这里@Configuration声明当前类是一个配置类。
* 使用@ComponentScan,自动扫描包下所有使用@Service、@Component、@Repository、@Controller的类,并注册为Bean。
*/
@Configuration
@ComponentScan("com.freesky.AnnotationConfiguration")
public class MyConfig {
}
应用入口类:
package com.freesky.AnnotationConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 测试主类
*
*/
public class App
{
public static void main( String[] args )
{
/**
* 使用AnnotationConfigApplicationContext作为Spring容器,接受输入一个配置类作为参数
*/
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
/**
* 获得声明配置的UseFunctionService的Bean
*/
UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
System.out.println( useFunctionService.sayHello("my world") );
}
}
运行结果较为简单,这里就不展示了。
二、Java配置
Java配置是Spring 4.x 推荐的配置方式,可以完全替代xml配置。Java配置也是Spring Boot 推荐的配置方式。
Java配置是通过@Configuration和@Bean来实现的。
* -@Configuration 声明当前类是一个配置类,相当于一个Spring配置的xml文件。
* -@Bean 注解在方法上,声明当前方法的返回值为一个Bean。
Java配置和注解配置的使用原则是:全局配置使用Java配置(如数据库相关配置、MVC相关配置),业务Bean的配置使用注解配置(@Service、@Component、@Repository、@Controller)。
下面将通过样例简单演示Java配置。
创建一个名为JavaConfiguration的Maven工程,pom.xml 文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.freesky</groupId>
<artifactId>JavaConfiguration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JavaConfiguration</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- 添加spring framework 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
</project>
创建功能类:
package com.freesky.JavaConfiguration;
/**
* 此处无需使用 @Service 声明Bean
*
*/
public class FunctionService {
public String sayHello(String word) {
return "Hello " + word + " !";
}
}
创建功能的使用类:
package com.freesky.JavaConfiguration;
/**
* 此处无需使用 @Service 声明 Bean
*
*/
public class UseFunctionService {
/**
* 此处无需使用 @Autowired 注解注入 Bean
*/
FunctionService functionService;
public void setFunctionService(FunctionService functionService) {
this.functionService = functionService;
}
public String sayHello(String word) {
return functionService.sayHello(word);
}
}
创建配置类:
package com.freesky.JavaConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* 使用 @Configuration 注解表明当前类是一个配置类,这意味着这个类里可能有0个或者多个@Bean注解,此处没有使用包扫描,是因为所有的Bean都在此类中定义了。
*
*/
@Configuration
public class JavaConfig {
/**
* 使用 @Bean 注解声明当前方法FunctionService的返回值是一个Bean,Bean的名称是方法名。
*/
@Bean
public FunctionService functionService() {
return new FunctionService();
}
@Bean
public UseFunctionService useFunctionService() {
UseFunctionService useFunctionService = new UseFunctionService();
// 注入FunctionService的Bean时候直接调用functionService()
useFunctionService.setFunctionService(functionService());
return useFunctionService;
}
/**
* 另外一种注入的方式,直接将FunctionService 作为参数给useFunctionService(),这也是Spring容器提供的极好的功能。
* 在Spring容器中,只要容器中存在某个Bean,就可以在另外一个Bean的声明方法的参数中注入。
*/
// @Bean
// public UseFunctionService useFunctionService(FunctionService functionService){
// UseFunctionService useFunctionService = new UseFunctionService();
// useFunctionService.setFunctionService(functionService);
// return useFunctionService;
// }
}
应用入口程序进行测试验证:
package com.freesky.JavaConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Java配置测试类
*
*/
public class App
{
public static void main( String[] args )
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
System.out.println( useFunctionService.sayHello("My JavaConfig") );
}
}
运行结果比较简单,这里不再展示。
三、小结
随着 Spring 不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,违背了最初的理念,甚至人称配置地狱。Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用 Spring 、更容易的集成各种常用的中间件、开源软件;另一方面,Spring Boot 诞生时,正处于微服务概念在慢慢酝酿中,Spring Boot 的研发融合了微服务架构的理念,实现了在 Java 领域内微服务架构落地的技术支撑。
Spring Boot 作为一套全新的框架,来源于 Spring 大家族,因此 Spring 所有具备的功能它都有,而且更容易使用;Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。Spring Boot 开发了很多的应用集成包,支持绝大多数开源软件,让我们以很低的成本去集成其他主流开源软件。