Spring Boot 配置与注解

2020-04-19  本文已影响0人  Minnakey

. Spring 是一个“引擎”;
. Spring MVC 是基于Spring的一个 MVC 框架;
. Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。

整理自:
https://mp.weixin.qq.com/s/nOx6iRfhPWWl2vKTSQ52Hg
https://mp.weixin.qq.com/s/ztM0VRgSLUZMK4sZ4rVFwA
https://mp.weixin.qq.com/s/OaMaT-QF20P65tKOjC5_oA

Spring Boot 自动配置

注解

Spring Boot 怎么做自动配置的?

SpringBoot自动配置

从代码里看项目SpringBoot的项目启动类只有一个注解@SpringBootApplication和一个run方法。

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

@SpringBootApplication:包含了@SpringBootConfiguration(打开是@Configuration),@EnableAutoConfiguration,@ComponentScan注解。

1. @Configuration

用一个过滤器举例,JavaConfig的配置方式是这样

@Configurationpublic 
class DruidConfiguration {        
    @Bean    
     public FilterRegistrationBean statFilter(){       
         //创建过滤器        
           FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());        
          //设置过滤器过滤路径        
           filterRegistrationBean.addUrlPatterns("/*");        
          //忽略过滤的形式        
           filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");        
           return filterRegistrationBean;   
 }}

任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。

2. @ComponentScan

@ComponentScan对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
注:所以SpringBoot的启动类最好是放在rootpackage下,因为默认不指定basePackages。

3. @EnableAutoConfiguration

借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {    
  String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
       Class<?>[] exclude() default {};
       String[] excludeName() default {};
}

@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。该配置模块的主要使用到了SpringFactoriesLoader
SpringFactoriesLoader: 类加载器,spring.factories文件,文件中对应的类则是接口的实现类
AutoConfigurationImportSelector: ImportSelector在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表,类信息加载到 JVM。

4. IOC

理论:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护。
​   ●谁依赖于谁:当然是应用程序依赖于IoC容器;
​   ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
​   ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
​   ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
目的:创建对象并且组装对象之间的关系
BeanApplication容器
​   ●org.springframework.beans : BeanFactroy提供配置结构和基本功能,加载并初始化Bean
​   ●org.springframework.context :ApplicationContext保存了Bean对象并在Spring中被广泛使用
​   ●标签: @Component、@Repository、@Service、@Controller、@Autowired
​   ●注入方式:属性注入、构造器注入
​   ●初始化方式:文件、Classpath,Web应用

5. MVC

主要组件:前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器HandlerAdapter、处理器Handler(需要工程师开发)、视图解析器View resolver(jstlView、freemarkerView、pdfView)

6. MyBatis

Maven:依赖starter就可以依赖到所有需要自动配置的类,实现开箱即用的功能
MyBatis 支持定制化 SQL、存储过程以及高级映射:
​   ●MyBatis使用SqlSessionFactoryBuilder来完成连接
​   ●MyBatis可以将SQL代码写入xml中,使用简单的 XML 或注解来配置和映射原生信息
​   ●MyBatis的mapper会自动将执行后的结果映射到对应的Java对象中,映射成数据库中的记录
组件:SqlSessionFactoryBuilder连接数据库、SqlSessionFactory数据源、SqlSession增删改查方法
缺点: SQL 工作量大

7. mybatis plus

特性:
  ●无侵入:Mybatis 的增强工具,只做增强不做改变;
  ●依赖少:仅仅依赖 Mybatis 以及 Mybatis-Spring,
  ●损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  ●预防Sql注入:内置 Sql 注入剥离器,有效预防Sql注入攻击
  ●通用CRUD操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  ●多种主键策略:支持多达4种主键策略(内含分布式唯一ID生成器),可自由配置,完美解决主键问题
  ●支持热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
  ●支持ActiveRecord:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可实现基本 CRUD 操作Active Record 是一种数据访问设计模式,它可以帮助你实现数据对象Object到关系数据库的映射。
  ●支持代码生成:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(P.S. 比 Mybatis 官方的 Generator 更加强大!)
  ●支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  ●支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
  ●内置分页插件:基于 Mybatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List查询
  ●内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能有效解决慢查询
  ●内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,预防误操作

注解

1、注解(annotations)列表

  1. @SpringBootApplication
    包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。
    其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文。

  2. @Component 可配合CommandLineRunner使用,在程序启动后执行一些基础任务。

  3. @RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。

  4. @Autowired自动导入。

  5. @PathVariable获取参数。

  6. @JsonBackReference解决嵌套外链问题。

  7. @RepositoryRestResourcepublic配合spring-boot-starter-data-rest使用。

2、注解(annotations)详解

package com.example.myproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // same as @Configuration @EnableAutoConfiguration @ComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@ResponseBody
public String test(){
    return”ok”;
}
@Controller
@RequestMapping(“/demoInfo”)
publicclass DemoController {
    @Autowired
    private DemoInfoService demoInfoService;

    @RequestMapping("/hello")
    public String hello(Map map){
        System.out.println("DemoController.hello()");
        map.put("hello","from TemplateController.helloHtml");
        //会使用hello.html或者hello.ftl模板进行渲染显示.
        return"/hello";
    }
}
package com.kfit.demo.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(“/demoInfo2”)
publicclass DemoController2 {

    @RequestMapping("/test")
    public String test(){
        return"ok";
    }
}
@Value(value = “#{message}”)
private String message;
@Autowired
@Qualifier(value = “demoInfoService”)
private DemoInfoService demoInfoService;

3、JPA注解

4、springMVC相关注解

@RequestParam
String a =request.getParameter(“a”)。
@PathVariable:路径变量。如
RequestMapping(“user/get/mac/{macAddress}”)
public String getByMacAddress(@PathVariable String macAddress){
    //do something;
}参数与大括号里的名字一样要相同。

5、mybatis-plus常用注解

6、全局异常处理

7、@Transactional 注解六种失效场景

1. 事务

事务管理在系统开发中是不可缺少的一部分,Spring提供了很好事务管理机制,主要分为编程式事务和声明式事务两种。
编程式事务:是指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强,如下示例:

try {
    //TODO something
     transactionManager.commit(status);
} catch (Exception e) {
    transactionManager.rollback(status);
    throw new InvoiceApplyException("异常失败");
}

声明式事务:基于AOP面向切面的,它将具体业务与事务处理部分解耦,代码侵入性很低,所以在实际开发中声明式事务用的比较多。声明式事务也有两种实现方式,一是基于TX和AOP的xml配置文件方式,二种就是基于@Transactional注解了。

   @Transactional
   @GetMapping("/test")
    public String test() {
        int insert = cityInfoDictMapper.insert(cityInfoDict);
    }
2. @Transactional介绍

1)、@Transactional注解可以作用于哪些地方?
@Transactional 可以作用在接口、类、类方法。

 @Transactional
 @RestController
 @RequestMapping
 public class MybatisPlusController {
    @Autowired
     private CityInfoDictMapper cityInfoDictMapper;
 
     @Transactional(rollbackFor = Exception.class)
     @GetMapping("/test")
    public String test() throws Exception {
        CityInfoDict cityInfoDict = new CityInfoDict();
        cityInfoDict.setParentCityId(2);
       cityInfoDict.setCityName("2");
        cityInfoDict.setCityLevel("2");
       cityInfoDict.setCityCode("2");
        int insert = cityInfoDictMapper.insert(cityInfoDict);
        return insert + "";
    }
}

2)、@Transactional注有哪些属性?

propagation 代表事务的传播行为,默认值为 Propagation.REQUIRED,其他的属性信息如下:

isolation :事务的隔离级别,默认值为 Isolation.DEFAULT。

timeout :事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
rollbackFor :用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。

3. @Transactional失效场景

1). @Transactional 应用在非 public 修饰的方法上
因为在Spring AOP 代理时,TransactionInterceptor (事务拦截器)在目标方法执行前后进行拦截,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法,获取Transactional 注解的事务配置信息。

protected TransactionAttribute computeTransactionAttribute(Method method,
    Class<?> targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
}

此方法会检查目标方法的修饰符是否为 public,不是 public则不会获取@Transactional 的属性配置信息。
注意:protected、private 修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错,这是我们很容犯错的一点。

2). @Transactional 注解属性 propagation 设置错误
这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。

3). @Transactional 注解属性 rollbackFor 设置错误
rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor属性。

4). 同一个类中方法调用,导致@Transactional失效
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。

那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

5). 异常被你的 catch“吃了”导致@Transactional失效
如果B方法内部抛了异常,而A方法此时try catch了B方法的异常,那这个事务还能正常回滚吗?
答案:不能!
会抛出异常:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolle
因为当ServiceB中抛出了一个异常以后,ServiceB标识当前事务需要rollback。但是ServiceA中由于你手动的捕获这个异常并进行处理,ServiceA认为当前事务应该正常commit。此时就出现了前后不一致,也就是因为这样,抛出了前面的UnexpectedRollbackException异常。

spring的事务是在调用业务方法之前开始的,业务方法执行完毕之后才执行commit or rollback,事务是否执行取决于是否抛出runtime异常。如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。

在业务方法中一般不需要catch异常,如果非要catch一定要抛出throw new RuntimeException(),或者注解中指定抛异常类型@Transactional(rollbackFor=Exception.class),否则会导致事务失效,数据commit造成数据不一致,所以有些时候try catch反倒会画蛇添足。

6). 数据库引擎不支持事务
这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。

上一篇 下一篇

猜你喜欢

热点阅读