[Spring Boot 系列教程] 项目结构及自动配置机制

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/github_39939645/article/details/86617248

上一篇文章中,介绍了 Spring Boot 的构建工具及原理,本篇文章将介绍 Spring Boot 项目的结构及配置。

项目结构

Spring Boot 虽然不需要任何特定的代码布局,但是,官方还是提供了一些最佳实践,下面将一一介绍。

包命名规范

java 的类不在任何一个包下面的时候,将会使用默认的包,但是这是不建议使用的,任何 java 类都应该在某个包下面,一般来说,Java 的包命名规范为将域名反过来写,如:https://www.docs4dev.com 这个域名,对应的包就是 com.docs4dev.项目名称(在教程中使用的包名就是:com.docs4dev.springboot)。

项目布局

我们知道 Spring Boot 可以通过 @SpringBootApplication 注解扫描项目的 Bean 和配置项,它是个组合注解,来看下它的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

}

这里有一个 @ComponentScan 的注解,它用于 Spring Boot 扫描 Bean 和配置。

Spring Boot 官方推荐将标记有 @SpringBootApplication 注解的启动类放到项目的 Root package 下,因为 @SpringBootApplication 会默认搜索当前包以及子包(scanBasePackages),查找系统配置(如:JPA 配置)。以下是官方推荐的项目布局:

com
 +- example
     +- myproject
         +- Application.java
         |
         +- domain
         |   +- Customer.java
         |   +- CustomerRepository.java
         |
         +- service
         |   +- CustomerService.java
         |
         +- web
             +- CustomerController.java

其中,Application.java 就是系统启动类,domain 包一般是放置 JPAEntityservice 包是业务逻辑层,web 包是 View 层,用于对外提供接口。你还可以根据自身需求添加相应的包,如 util 包常用于存放工具类。

系统配置

Spring Boot 中,可以使用传统的 xml 方式来配置相关的属性,也可以使用 Java 代码的方式进行配置,官方推荐是以 Java 代码的方式进行配置,这样不仅更灵活而且也比 xml 方式更简洁。

当我们需要新增某个配置的时候,可以为其添加 @Configuration 注解,Spring Boot 会自动扫描标记有 @Configuration 的类并将其注册为 Bean,这样就可以直接在项目中使用了。

当你有许多的配置项时,不需要将它们全部放到一个类中,Spring Boot 提供了一个注解@Import ,它可以将多个配置类聚合。如果因为历史原因,你需要导入 xml 配置,Spring Boot 也提供了另一个注解 @ImportResource 来做这件事。

自动配置

在上面 @SpringBootApplication 的源码中,我们还可以看到另一个注解 @EnableAutoConfiguration ,它使得 Spring Boot 可以自动的帮我们进行一些设置,例如你在项目中添加了 @EnableAutoConfiguration 注解或是直接使用了 @SpringBootApplication 注解,并在 classpath 中存在 HSQLDB 的依赖,你无须做任何事情,就可以直接在项目中使用 HSQLDB 相关的操作。

我们还是通过 https://start.spring.io/ 来创建新的工程,并选择 JPA Lombok HSQLDB ,以下是 mavandependencies配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

接下来我们编写 JPAEntity RepositoryJunit 测试类:

Entity

@Getter
@Setter
@Entity
@Table(name ="user")
public class User {

    @Id
    @GeneratedValue
    private Long id;
    private String username;
}

Repository


public interface UserRepository extends JpaRepository<User, Long> {

}

单元测试

@SpringBootTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void autoconfigTest() {
        User user = new User();
        user.setUsername("tom");
        userRepository.save(user);
        User dbUser = userRepository.findById(user.getId()).orElseThrow(RuntimeException::new);
        assertThat(dbUser).isEqualToComparingFieldByField(user);
    }
}

除此之外,不需要其它操作,我们没有配置任何关于数据库连接的信息,让我们运行以上测试,会发现测试会完美通过,没有任何异常,这就是 Spring Boot @EnableAutoConfiguration 的魔力,它帮我们大大简化了开发中这些重复性的工作。

替换默认配置

Spring Boot 提供的自动配置功能虽然非常强大,但是某些时候我们还是需要自定义配置项,这个时候,我们就可以禁用 Spring Boot 的自动配置并提供自己的配置,这个实现非常简单,就是通过 SpringBootApplication 中的 exclude 参数禁用某些配置,自行编写相关配置项后添加 @Configuration 注解即可,例如在此处我们禁用 SPring BootDataSourceAutoConfiguration ,并添加自己的 MyCustomDataSourceConfigration

import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
@Configuration
public class MyCustomDataSourceConfigration {
}

Spring Bean 注入

Spring Boot 中,你可以使用 Spring 中任何的 Bean 注入方式(构造器注入,Setter 注入等),同时它也支持 Spring 中定义 Bean 的注解(如: @Component, @Service, @Repository, @Controller 等等),标记了这些注解的类都会被 @ComponentScan 加载为 Spring Bean

结语

关于 Spring Boot 的配置就讲到此处了,下一篇文章将介绍 spring-boot-devtools

展开阅读全文

Spring Boot自动配置实例

12-20

spring boot之所以能够自动配置bean,是通过基于条件来配置Bean的能力实现的。rnrn常用的条件注解如下rnrn@ConditionalOnBean:当容器里存在指定的Bean的条件下rnrn@ConditionalOnClass:当前类路径下存在指定的类的条件下rnrn@ConditionalOnExpression:基于SpEL表达式作为判断条件rnrn@ConditionalOnJava:基于JVM版本作为判断条件rnrn@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置rnrn@ConditionalOnMissingBean:当容器里没有指定的Bean的条件下rnrn@ConditionalOnMissingClass:当前类路径下没有指定的类的条件下rnrn@ConditionalOnNotWebApplication:当前项目不是web项目的条件下rnrn@ConditionalOnProperty:指定的属性是否有指定的值的条件下rnrn@ConditionalOnResource:类路径下是否有指定的值rnrn@ConditionalOnSingleCandidate:指定Bean在容器中只有一个,或者虽然有多个但是指定首选的Beanrnrn@ConditionalOnWebApplication:当前项目是Web项目的条件下rnrn这些注解都组合了@Conditional注解,只是使用了不同的条件。rnrn接下来我们自己写一个自动配置,并且封装成starter pom。rnrn首先创建maven工程,导入以下依赖:rnrnrn org.springframework.bootrn spring-boot-autoconfigurern 1.3.8.RELEASErn rn工程结构如下rn[img=https://img-bbs.csdn.net/upload/201612/20/1482201836_19178.png][/img]rn创建AuthorProperties类,作为配置信息的载体rn[code=java]package com.springboot.springboot_starter_hello;rnrnimport org.springframework.boot.context.properties.ConfigurationProperties;rnrn@ConfigurationProperties(prefix="author")//指定配置内容的前缀rnpublic class AuthorProperties rn rn private static final String NAME = "微儿博客";rnrn private static final int AGE = 18;rn rn private String name = NAME;//默认为微儿博客rn rn private int age = AGE;//默认为18rnrn public String getName() rn return name;rn rnrn public void setName(String name) rn this.name = name;rn rnrn public int getAge() rn return age;rn rnrn public void setAge(int age) rn this.age = age;rn rn[/code] rn创建AuthorService类,作为Beanrn[code=java]package com.springboot.springboot_starter_hello;rnrnpublic class AuthorService rn rn private String name;rn rn private int age;rn rn public String who()rn return "name:"+name+",age:"+age;rn rnrn public String getName() rn return name;rn rnrn public void setName(String name) rn this.name = name;rn rnrn public int getAge() rn return age;rn rnrn public void setAge(int age) rn this.age = age;rn rn[/code]rn创建配置类AuthorServiceAutoConfiguration,负责配置Beanrn[code=java]package com.springboot.springboot_starter_hello;rnrnimport org.springframework.beans.factory.annotation.Autowired;rnimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;rnimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;rnimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;rnimport org.springframework.boot.context.properties.EnableConfigurationProperties;rnimport org.springframework.context.annotation.Bean;rnimport org.springframework.context.annotation.Configuration;rnrn@Configuration//声明配置类rn@EnableConfigurationProperties(AuthorProperties.class)rn@ConditionalOnClass(AuthorService.class)//类路径下存在AuthorService类的条件下rn@ConditionalOnProperty(prefix="author",value="enabled",matchIfMissing=true)//在前缀为author的配置为enabled的情况下,即author=enabled,没有配置默认为enabledrnpublic class AuthorServiceAutoConfiguration rnrn @Autowiredrn private AuthorProperties authorProperties;rn rn @Beanrn @ConditionalOnMissingBean(AuthorService.class)//容器中没有AuthorService的Bean的条件下配置该Beanrn public AuthorService authorService()rn AuthorService authorService = new AuthorService();rn authorService.setName(authorProperties.getName());rn authorService.setAge(authorProperties.getAge());rn return authorService;rn rn[/code]rn若想自动配置生效,需要注册自动配置类。在src/main/resources下创建META-INF/spring.factories文件,并写入以下内容:rn[code=text]org.springframework.boot.autoconfigure.EnableAutoConfiguration=\rncom.springboot.springboot_starter_hello.AuthorServiceAutoConfiguration[/code]rn若有多个自动配置类,则用","隔开,此处“\”是为了换行后仍能读到属性。rn以上操作完成后执行maven install。rn然后在Spring Boot项目中引入该依赖:rn[code=text]rn com.springbootrn springboot-starter-hellorn 0.0.1-SNAPSHOTrn[/code]rn新建AutoConfig类:rn[code=java]package com.springboot.autoconfig;rnrnimport org.springframework.beans.factory.annotation.Autowired;rnimport org.springframework.boot.SpringApplication;rnimport org.springframework.boot.autoconfigure.SpringBootApplication;rnimport org.springframework.web.bind.annotation.RequestMapping;rnimport org.springframework.web.bind.annotation.RestController;rnrnimport com.springboot.springboot_starter_hello.AuthorService;rnrn@SpringBootApplicationrn@RestControllerrnpublic class AutoConfig rn rn @Autowiredrn private AuthorService authorService;rn rn @RequestMapping("/")rn public String who()rn return authorService.who();rn rn rn public static void main(String[] args) rn SpringApplication.run(AutoConfig.class, args);rn rn[/code]rn运行该类,访问localhost:8080,出现如下结果:name:微儿博客,age:18rn[img=https://img-bbs.csdn.net/upload/201612/20/1482202010_889306.png][/img]rn接下来在src/main/resources下新建application.properties文件,写入以下内容:rn[code=text]author.name=wearernauthor.age=19[/code]rn重新运行AutoConfig类:name:weare,age:19rn[img=https://img-bbs.csdn.net/upload/201612/20/1482202032_235931.png][/img]rn原文链接:[url=http://www.weare.net.cn/article/48db8546ed9e4eed8a9a3f5ca81e64ab.html]点击访问​[/url]rnrn更多文章请访问 [url=http://www.weare.net.cn]微儿博客[/url] 论坛

没有更多推荐了,返回首页