zoukankan      html  css  js  c++  java
  • 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-demosrc">
                <property name="enableSubPackages" value="true"/>
                <property name="trimStrings" value="true"/>
            </javaModelGenerator>
            <!--生成映射文件存放位置-->
            <sqlMapGenerator targetPackage="mapper" targetProject="springboot-demosrc">
                <property name="enableSubPackages" value="true"/>
            </sqlMapGenerator>
            <!--生成mapper类存放位置-->
            <javaClientGenerator type="XMLMAPPER" targetPackage="lddxfs.springboot.springbootdemo.mapper" targetProject="springboot-demosrc">
                <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

  • 相关阅读:
    BZOJ 1101 莫比乌斯函数+分块
    BZOJ 2045 容斥原理
    BZOJ 4636 (动态开节点)线段树
    BZOJ 2005 容斥原理
    BZOJ 2190 欧拉函数
    BZOJ 2818 欧拉函数
    BZOJ 3123 主席树 启发式合并
    812. Largest Triangle Area
    805. Split Array With Same Average
    794. Valid Tic-Tac-Toe State
  • 原文地址:https://www.cnblogs.com/LDDXFS/p/springboot.html
Copyright © 2011-2022 走看看