springboot自动配置原理 and 一个简单的demo项目 and spring常用注解的使用

Springboot自动配置原理:

主类 @SpringBootApplication 开启了自动配置

@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 {
...
}
@Import(EnableAutoConfigurationImportSelector.class) 通过注解的方式实现把实例EnableAutoConfigurationImportSelector加入springIOC容器中,
EnableAutoConfigurationImportSelector实现了接口ImportSelector,并在其父类AutoConfigurationImportSelector中实现了ImportSelector定义的
org.springframework.context.annotation.ImportSelector#selectImports 【String[] selectImports(AnnotationMetadata importingClassMetadata)】),
selectImports返回了一系列的***AutoConfiguration配置类,例如org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,具体返回内容请查看动图一 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...
}

org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration 中通过注解 @ConditionalXXX 定义了创建bean的条件 ,

例如下面代码片段的 @ConditionalOnMissingBean(CharacterEncodingFilter.class)定义了当CharacterEncodingFilter类型的bean不存在才创建bean,当我们通过maven引入某个starter后(例如 spring-boot-starter-web),会匹配@Conditional定义的条件从而创建bean
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnWebApplication
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    private final HttpEncodingProperties properties;

    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }
...
}

 

自动化配置类都有一个这样的注解@EnableConfigurationProperties ,例如 @EnableConfigurationProperties(HttpEncodingProperties.class) 来关联配置文件(application.yml或application.properties)的内容,可以打开这些类来看支持哪些配置项

 

 

一个简单的demo项目

下面贴出部分代码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>lddxfs.springboot</groupId>
    <artifactId>springboot-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>springboot-demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.18.BUILD-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>-->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <!-- Provided -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <!-- <dependency>
             <groupId>org.apache.tomcat.embed</groupId>
             <artifactId>tomcat-embed-jasper</artifactId>
             <scope>provided</scope>
         </dependency>-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
        <pluginRepository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>


</project>
View Code

入口类

package lddxfs.springboot.springbootdemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement
@MapperScan("lddxfs.springboot.springbootdemo.mapper")
public class SpringbootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.class, args);
    }

}

yml

application:
  message: bootJSP
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dubbostudy?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  mvc:
    view:
      prefix: /WEB-INF/jsp/
      suffix: .jsp
    formcontent:
      putfilter:
        enabled: true
  http:
    encoding:
      charset: utf-8
      force: true
mybatis:
  mapper-locations: classpath*:mapper\*.xml
View Code

使用外部tomcat运行(支持jsp)

package lddxfs.springboot.springbootdemo;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/24
 * 使用外置tomcat
 */
public class DemoSpringBootServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringbootDemoApplication.class);
    }
}
View Code

监听器

package lddxfs.springboot.springbootdemo.web; /**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/24
 */

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 *  Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 *  Date:2018/10/23
 */
public class DemoListener implements ServletContextListener,
        HttpSessionListener, HttpSessionAttributeListener {
    private static Logger log = LoggerFactory.getLogger(DemoListener.class);
    public DemoListener() {
    }

    // -------------------------------------------------------
    // ServletContextListener implementation
    // -------------------------------------------------------
    public void contextInitialized(ServletContextEvent sce) {
      /* This method is called when the servlet context is
         initialized(when the Web application is deployed). 
         You can initialize servlet context related data here.
      */
        log.info("容器启动了");
    }

    public void contextDestroyed(ServletContextEvent sce) {
      /* This method is invoked when the Servlet Context 
         (the Web application) is undeployed or 
         Application Server shuts down.
      */
        log.info("容器销毁了");
    }

    // -------------------------------------------------------
    // HttpSessionListener implementation
    // -------------------------------------------------------
    public void sessionCreated(HttpSessionEvent se) {
        /* Session is created. */
        log.info("Session创建了 sessionId:{}",se.getSession().getId());
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        /* Session is destroyed. */
        log.info("Session销毁了 sessionId:{}",se.getSession().getId());
    }

    // -------------------------------------------------------
    // HttpSessionAttributeListener implementation
    // -------------------------------------------------------

    public void attributeAdded(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute 
         is added to a session.
      */
        log.info("放入值到Session了 name:{}",sbe.getName());
    }

    public void attributeRemoved(HttpSessionBindingEvent sbe) {
      /* This method is called when an attribute
         is removed from a session.
      */
        log.info("Session移除值 name:{}",sbe.getName());
    }

    public void attributeReplaced(HttpSessionBindingEvent sbe) {
      /* This method is invoked when an attibute
         is replaced in a session.
      */
        log.info("Session修改值 name:{}",sbe.getName());
    }
}
View Code

  过滤器

package lddxfs.springboot.springbootdemo.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/24
 */
public class DemoFilter implements Filter {
    private static Logger log = LoggerFactory.getLogger(DemoFilter.class);

    @Override
    public void init(FilterConfig filterConfig) {
        log.info("DemoFilter.init()");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            HttpServletRequest req = (HttpServletRequest) request;
            log.info("请求uri:{}", req.getRequestURI());
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        log.info("DemoFilter.destroy()");
    }
}
View Code

三大组件注册配置类

package lddxfs.springboot.springbootdemo.config;

import lddxfs.springboot.springbootdemo.web.DemoFilter;
import lddxfs.springboot.springbootdemo.web.DemoListener;
import lddxfs.springboot.springbootdemo.web.DemoServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashSet;
import java.util.Set;

/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/23
 * web三大组件注册配置类
 */
@Configuration
public class WebBeanConfig {

    /**
     * 注册serlet
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new DemoServlet());
        servletRegistrationBean.addUrlMappings("/testServletA");
        return servletRegistrationBean;
    }

    /**
     * 注册filter
     * @return
     */
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new DemoFilter());
        filterRegistrationBean.setOrder(0);
        Set<String> urlPatterns = new HashSet<>();
        urlPatterns.add("/*");
        filterRegistrationBean.setUrlPatterns(urlPatterns);
        return filterRegistrationBean;
    }



    /**
     * 注册listener
     * @return
     */
    @Bean
    public ServletListenerRegistrationBean servletListenerRegistrationBean() {
        ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
        servletListenerRegistrationBean.setListener(new DemoListener());
        servletListenerRegistrationBean.setOrder(0);
        return servletListenerRegistrationBean;
    }
}
View Code

异常处理

package lddxfs.springboot.springbootdemo.web;

import lddxfs.springboot.springbootdemo.common.resutcode.Result;
import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/24
 */
@Component
public class DemoErrorAttribute extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
        Result<Void> result =(  Result<Void>)requestAttributes.getAttribute("ext",RequestAttributes.SCOPE_REQUEST);
        Map<String, Object> errorMap=new LinkedHashMap<>();
        errorMap.put("message",result.getMessage());
        errorMap.put("data",result.getData());
        errorMap.put("code",result.getCode());
        return errorMap;
    }
}
View Code
package lddxfs.springboot.springbootdemo.web;

import lddxfs.springboot.springbootdemo.common.resutcode.Result;
import lddxfs.springboot.springbootdemo.common.resutcode.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;

/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/24
 * 异常处理
 */
@ControllerAdvice
public class DemoExeceptionHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(DemoExeceptionHandler.class);

    /**
     * 所有客户端返回json数据
     *
     * @param e
     * @return
     */
/*    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Result<Void> HandleException(Exception e) {
        Result<Void> result = ResultCode.ERROR.clone();
        result.setMessage(e.getMessage());
        return result;
    }*/

    /**
     * 不同客户端返回JSON或Html
     * @param e
     * @param request
     * @return
     */
    @ExceptionHandler(Exception.class)
    public String handleException(Exception e, HttpServletRequest request) {
        Result<Void> result = ResultCode.ERROR.clone();
        result.setMessage(e.getMessage());
        request.setAttribute("ext", result);
        request.setAttribute("javax.servlet.error.status_code", HttpStatus.INTERNAL_SERVER_ERROR.value());
        LOGGER.error("系统异常:", e);
        return "forward:/error";
    }
}
View Code

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    <display-name>springboot-demo</display-name>
</web-app>
View Code

Controller

package lddxfs.springboot.springbootdemo.web.controller;

import lddxfs.springboot.springbootdemo.common.resutcode.Result;
import lddxfs.springboot.springbootdemo.common.resutcode.ResultCode;
import lddxfs.springboot.springbootdemo.javabean.Category;
import lddxfs.springboot.springbootdemo.service.CategoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;


/**
 * Author:lddxfs(lddxfs@qq.com;https://www.cnblogs.com/LDDXFS/)
 * Date:2018/10/6
 * REST风格 管理分类
 */
@RequestMapping("api")
@RestController
public class CategoryController {
    private static Logger logger = LoggerFactory.getLogger(CategoryController.class);
    @Resource
    private CategoryService categoryService;

    @GetMapping("categories")
    public Result<List<Category>> categories() {
        Result<List<Category>> result = ResultCode.SUCCESS.clone();
        result.setData(categoryService.categories());
        return result;
    }

    public CategoryController() {
        System.out.println("CategoryController");
    }

    @GetMapping("/categories/{id}")
    public Result<Category> categories(@PathVariable("id") Integer id) {
        Result<Category> result = ResultCode.SUCCESS.clone();
        result.setData(categoryService.categoriesById(id));
        return result;
    }

    @DeleteMapping("/categories/{id}")
    public Result<Void> deleteCategories(@PathVariable("id") Integer id) {
        Result<Void> result = ResultCode.SUCCESS.clone();
        categoryService.deleteCategories(id);
        return result;
    }

    @PutMapping("/categories")
    public Result<Category> updateCategories(Category category) {
        Result<Category> result = ResultCode.SUCCESS.clone();
        result.setData(categoryService.updateCategories(category));
        return result;
    }

    @PostMapping("/categories")
    public Result<Category> createCategories(Category category) {
        Result<Category> result = ResultCode.SUCCESS.clone();
        result.setData(categoryService.saveCategories(category));
        return result;
    }

    @PostMapping(value = "/categories/transaction_test")
    public Result<List<Category>> transactionTest(@RequestBody List<Category> categories) {
        Result<List<Category>> result = ResultCode.SUCCESS.clone();
        result.setData(categoryService.transactionTest(categories));
        return result;
    }

}
View Code

mybatis代码生成配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--数据库驱动-->
    <classPathEntry    location="mysql-connector-java-5.1.45.jar"/>
    <context id="mysql">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>
        <!--数据库链接地址账号密码-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/dubbostudy?useSSL=true" userId="root" password="123456">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!--生成Model类存放位置-->
        <javaModelGenerator targetPackage="lddxfs.springboot.springbootdemo.javabean" targetProject="springboot-demo\src">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!--生成映射文件存放位置-->
        <sqlMapGenerator targetPackage="mapper" targetProject="springboot-demo\src">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!--生成mapper类存放位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="lddxfs.springboot.springbootdemo.mapper" targetProject="springboot-demo\src">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!--生成对应表及类名-->

        <table tableName="tb_good_category" domainObjectName="Category" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
        <!--<generatedKey column="id" sqlStatement="mySql"></generatedKey>-->
            <generatedKey column="id" sqlStatement="JDBC" identity="true" type="post"/>
        </table>

    </context>
</generatorConfiguration>
View Code

 

其他代码就不贴了

idea配置外部tomcat

 

补充spring常用注解的使用

上传代码到码云了,代码位置: https://gitee.com/lddxfs/spring-annotation-use

 

posted @ 2018-10-24 18:11  LDDXFS  阅读(346)  评论(0编辑  收藏  举报