目录
一、定义
二、作用域
三、解析方式
四、元注解
五、内置注解
5.1 @Override
5.2 @Deprecated
5.3 @SuppressWarnings
六、常用注解
6.1 @SpringBootApplication
6.2 @Controller
6.3 @RequestMapping、GetMapping、PostMapping
6.3.1、 value, method
6.3.2、 consumes,produces;
6.3.3、 params,headers;
6.4 @RequestBody
6.5 @Responsebody
6.6 @RequestParam
6.7 @Slf4j
6.8 @setter @getter
6.9 @data
6.10 @Transactional
6.11 @Resource 和 @Autowired
6.12 @value
6.13 @param
6.14 @EnableCaching、@Cacheable、@Cacheput 、@CacheEvict
6.15 @Conditional
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
注解:说明程序的(给计算机看)
注释:用文字描述程序的。(给程序员看)
注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量
一种是编译期直接的扫描,一种是运行期反射。而编译器的扫描指的是编译器在对 java 代码编译字节码的过程中会检测到某个类或者方法被一些注解修饰,这时它就会对于这些注解进行某些处理。
典型的就是注解 @Override,一旦编译器检测到某个方法被修饰了 @Override 注解,编译器就会检查当前方法的方法签名是否真正重写了父类的某个方法,也就是比较父类中是否具有一个同样的方法签名。
这一种情况只适用于那些编译器已经熟知的注解类,比如 JDK 内置的几个注解,而你自定义的注解,编译器是不知道你这个注解的作用的,当然也不知道该如何处理,往往只是会根据该注解的作用范围来选择是否编译进字节码文件,仅此而已。
是用于修饰注解的注解
import java.lang.annotation.*;
/**
* @program: annotation
* @description
* @author: hk
* @create: 2019-08-13 10:28
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Inherited
public @interface AnnotationTest {
String name() default "默认值张三";
}
@Documented 注解修饰的注解,当我们执行 JavaDoc 文档打包时会被保存进 doc 文档,反之将在打包时丢弃。
@Inherited 注解修饰的注解是具有可继承性的,也就说我们的注解修饰了一个类,而该类的子类将自动继承父类的该注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
没有任何的属性,所以并不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。
是一种典型的『标记式注解』,仅被编译器可知,编译器在对 java 文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹对父类中是否具有一个同样方法签名的函数,如果不是,自然不能通过编译。
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* A program element annotated @Deprecated is one that programmers
* are discouraged from using, typically because it is dangerous,
* or because a better alternative exists. Compilers warn when a
* deprecated program element is used or overridden in non-deprecated code.
*
* @author Neal Gafter
* @since 1.5
* @jls 9.6.3.6 @Deprecated
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
『标记式注解』,永久存在,可以修饰所有的类型,作用是,标记当前的类或者方法或者字段等已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。
当然,编译器并不会强制要求你做什么,只是告诉你 JDK 已经不再推荐使用当前的方法或者类了,建议你使用某个替代者。
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* Indicates that the named compiler warnings should be suppressed in the
* annotated element (and in all program elements contained in the annotated
* element). Note that the set of warnings suppressed in a given element is
* a superset of the warnings suppressed in all containing elements. For
* example, if you annotate a class to suppress one warning and annotate a
* method to suppress another, both warnings will be suppressed in the method.
*
* As a matter of style, programmers should always use this annotation
* on the most deeply nested element where it is effective. If you want to
* suppress a warning in a particular method, you should annotate that
* method rather than its class.
*
* @author Josh Bloch
* @since 1.5
* @jls 4.8 Raw Types
* @jls 4.12.2 Variables of Reference Type
* @jls 5.1.9 Unchecked Conversion
* @jls 5.5.2 Checked Casts and Unchecked Casts
* @jls 9.6.3.5 @SuppressWarnings
*/
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
/**
* The set of warnings that are to be suppressed by the compiler in the
* annotated element. Duplicate names are permitted. The second and
* successive occurrences of a name are ignored. The presence of
* unrecognized warning names is not an error: Compilers must
* ignore any warning names they do not recognize. They are, however,
* free to emit a warning if an annotation contains an unrecognized
* warning name.
*
*
The string {@code "unchecked"} is used to suppress
* unchecked warnings. Compiler vendors should document the
* additional warning names they support in conjunction with this
* annotation type. They are encouraged to cooperate to ensure
* that the same names work across multiple compilers.
* @return the set of warnings to be suppressed
*/
String[] value();
}
value 属性需要你主动的传值,这个 value 代表一个什么意思呢,这个 value 代表的就是需要被压制的警告类型。
包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan通常用在主类上;
@SpringBootConfiguration:这是Spring Boot项目的配置注解,这也是一个组合注解,与@Configuration作用相同,标识这是一个被装载的Bean,在Spring Boot项目中推荐使用@ SpringBootConfiguration替代@Configuration
@EnableAutoConfiguration:启用自动配置,该注解会使Spring Boot根据项目中依赖的jar包自动配置项目的配置项。类似Java SPI(Service Provider Interface)机制:我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。
面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,
如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
如:spring-boot依赖下META-INFO下spring.factories
@ComponentScan:默认扫描@SpringBootApplication所在类的同级目录以及它的子目录下@Controller、@Service、@Repository、@Component,默认扫描自己所在的包
basePackage 制定扫描的包(根目录开始)
includeFilters 包含的过滤器
excludeFilters 排除的过滤器。
@Controller用于标记在一个类上,使用它标记的类就是一个SpringMvc Controller对象,分发处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是处理请求的处理器。
@Controller标记在一个类上还不能真正意义上说它就是SpringMvc的控制器,应为这个时候Spring还不认识它,这个时候需要把这个控制器交给Spring来管理
当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。
RestController相当于Controller+ResponseBody注解
映射请求,也就是通过它来指定控制器可以处理哪些URL请求,类似于struts的action请求,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明。
value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
value的uri值为以下三类:
A) 可以指定为普通的具体值;
B) 可以指定为含有某变量的一类值(URI Template Patterns with Path Variables);
C) 可以指定为含正则表达式的一类值( URI Template Patterns with Regular Expressions);
example B)
@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
example C)
@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}")
public void handle(@PathVariable String version, @PathVariable String extension) {
// ...
}
}
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
cousumes的样例:
@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
// implementation omitted
}
方法仅处理request Content-Type为“application/json”类型的请求。
produces的样例:
@Controller
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
// implementation omitted
}
方法仅处理request请求中Accept头中包含了"application/json"的请求,同时暗示了返回的内容类型为application/json;
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
params的样例:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
仅处理请求中包含了名为“myParam”,值为“myValue”的请求;
headers的样例:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
仅处理request的header中包含了指定“Refer”请求头和对应值为“http://www.ifeng.com/”的请求;
它的作用在形参列表上,用于将前台发送过来固定格式的数据(xml格式或json等)封装为对应的JavaBean对象,封装时使用到的一个对象是系统默认配置的HttpMessageConverter进行解析,然后封装到形参上。
一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP responsebody中。
*比如异步获取json数据,加上@responsebody后,会直接返回json数据。*
@ResponseBody,可以帮我们把User序列化到resp.body中。@RequestBody可以帮我们把req.body的内容转化为User对象。如果是开发Web应用,一般这两个注解对应的就是Json序列化和反序列化的操作。这里实际上已经体现了Http序列化/反序列化这个过程,只不过和普通的对象序列化有些不一样,Http序列化/反序列化的层次更高,属于一种Object2Object之间的转换。
1、决定resp.body的Content-Type的第一要素是对应的req.headers.Accept属性的值,又叫做MediaType。如果服务端支持这个Accept,那么应该按照这个Accept来确定返回resp.body对应的格式,同时把resp.headers.Content-Type设置成自己支持的符合那个Accept的MediaType。服务端不支持Accept指定的任何MediaType时,应该返回错误406 Not Acceptable.
例如:req.headers.Accept = text/html,服务端支持的话应该让resp.headers.Content-Type = text/html,并且resp.body按照html格式返回。
例如:req.headers.Accept = text/asdfg,服务端不支持这种MediaType,应该返回406 Not Acceptable。
2、如果Accept指定了多个MediaType,并且服务端也支持多个MediaType,那么Accept应该同时指定各个MediaType的QualityValue,也就是q值,服务端根据q值的大小来决定这几个MediaType类型的优先级,一般是大的优先。q值不指定时,默认视为q=1.
Chrome的默认请求的Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,表示服务端在支持的情况下应该优先返回text/html,其次是application/xhtml+xml.
前面几个都不支持时,服务器可以自行处理 */*,返回一种服务器自己支持的格式。
3、一个HTTP请求没有指定Accept,默认视为指定 Accept: */*;没有指定Content-Type,默认视为 null,就是没有。当然,服务端可以根据自己的需要改变默认值。
4、Content-Type必须是具体确定的类型,不能包含 *.
启动时默认加载的Converter
ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;
StringHttpMessageConverter: 负责读取字符串格式的数据和写出二进制格式的数据;
ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;
FormHttpMessageConverter: 负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
MappingJacksonHttpMessageConverter: 负责读取和写入json格式的数据;
SouceHttpMessageConverter: 负责读取和写入 xml 中javax.xml.transform.Source定义的数据;
Jaxb2RootElementHttpMessageConverter: 负责读取和写入xml 标签格式的数据;
AtomFeedHttpMessageConverter: 负责读取和写入Atom格式的数据;
RssChannelHttpMessageConverter: 负责读取和写入RSS格式的数据;
WebMvcConfigurationSupport类
参数:
value:参数名字,即入参的请求参数名字,如username表示请求的参数区中的名字为username的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报404错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值,例如:
代替private final Logger logger = LoggerFactory.getLogger(当前类名.class);
springboot中1.安装Lombok插件;2.在pom文件加入lombok的依赖,spring中还需加入还需要slf4j以及它的实现,比如logback
生成的getter / setter方法默认将是public除非明确指定AccessLevel。逻辑访问级别PUBLIC,PROTECTED,PACKAGE,和PRIVATE
1、@Data可以为类提供读写功能,从而不用写get、set方法。 2、他还会为类提供 equals()、hashCode()、toString() 方法。
声明式事务
1.在 xml 配置文件中添加如清单 1 的事务配置信息。除了用配置文件的方式,@EnableTransactionManagement 注解也可以启用事务管理功能。
2.将@Transactional 注解添加到合适的类或方法上,并设置合适的属性信息
属性 |
类型 |
描述 |
value |
String |
可选的限定描述符,指定使用的事务管理器 |
propagation |
enum: Propagation |
可选的事务传播行为设置 |
isolation |
enum: Isolation |
可选的事务隔离级别设置 |
readOnly |
boolean |
读写或只读事务,默认读写 |
timeout |
int (in seconds granularity) |
事务超时时间设置 |
rollbackFor |
Class对象数组,必须继承自Throwable |
导致事务回滚的异常类数组 |
rollbackForClassName |
类名数组,必须继承自Throwable |
导致事务回滚的异常类名字数组 |
noRollbackFor |
Class对象数组,必须继承自Throwable |
不会导致事务回滚的异常类数组 |
noRollbackForClassName |
类名数组,必须继承自Throwable |
不会导致事务回滚的异常类名字数组 |
的事务之间的隔离程度
几点注意:
1、@Transactional 使用位置 类上方、方法上方,当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义
2、方法的访问权限为 public ,@Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常
3、默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰
例如一:同一个类中方法,A方法未使用此标签,B使用了,C未使用,A 调用 B , B 调用 C ;则外部调用A之后,B的事务是不会起作用的
例如二:若是有上层(按照 Controller层、Service层、DAO层的顺序)由Action 调用 Service 直接调用,发生异常会发生回滚;若间接调用,Action 调用 Service 中 的A 方法,A无@Transactional 注解,B有,A调用B,B的注解无效
4、spring 的事务管理是线程安全的
5、父类的声明的@Transactional会对子类的所有方法进行事务增强;子类覆盖重写父类方式可覆盖其@Transactional中的声明配置
6、类名上方使用@Transactional,类中方法可通过属性配置覆盖类上的@Transactional配置;比如:类上配置全局是可读写,可在某个方法上改为只读
1、@Autowird 属于spring注解,默认使用类型(byType)进行注入,这个接口只有一个实现类,那么会正常注入,如果有多个实现类,他会报错,如果没有实现类,它也会报错,配合@Qualifier或@Primary
@Autowired(required = false)
@Autowired
@Qualifier("userServiceImpl")
public IUserService userService;
或者
@Autowired
public void setUserDao(@Qualifier("userDao") UserDao userDao) {
this.userDao = userDao;
}
2、@Resource是JavaEE自带的注解,默认按byName自动注入
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配
1、不通过配置文件的注入属性的情况
通过@Value将外部的值动态注入到Bean中,使用的情况有:
@Value("normal")
private String normal; // 注入普通字符串
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性
@Value("#{ T(java.lang.Math).random() * 100.0 }")
private double randomNumber; //注入表达式结果
@Value("#{beanInject.another}")
private String fromAnotherBean; // 注入其他Bean属性:注入beanInject对象的属性another,类具体定义见下面
@Value("classpath:com/hry/spring/configinject/config.txt")
private Resource resourceFile; // 注入文件资源
@Value("http://www.baidu.com")
private Resource testUrl; // 注入URL资源
注入其他Bean属性:注入beanInject对象的属性another
@Component
public class BeanInject {
@Value("其他Bean的属性")
private String another;
public String getAnother() {
return another;
}
public void setAnother(String another) {
this.another = another;
}
}
2、通过@Value将外部配置文件的值动态注入到Bean中。配置文件主要有两类:
第一个属性文件config.properties内容如下:
${anotherfile.configinject}作为第二个属性文件加载路径的变量值
book.name=bookName anotherfile.configinject=placeholder
第二个属性文件config_placeholder.properties内容如下:
book.name.placeholder=bookNamePlaceholder
@Component
// 引入外部配置文件组:${app.configinject}的值来自config.properties。
// 如果相同
@PropertySource({"classpath:com/hry/spring/configinject/config.properties",
"classpath:com/hry/spring/configinject/config_${anotherfile.configinject}.properties"})
public class ConfigurationFileInject{
@Value("${app.name}")
private String appName; // 这里的值来自application.properties,spring boot启动时默认加载此文件
@Value("${book.name}")
private String bookName; // 注入第一个配置外部文件属性
@Value("${book.name.placeholder}")
private String bookNamePlaceholder; // 注入第二个配置外部文件属性
1.传递单个参数,不使用 @Param 注解
java 接口不使用 @Param 注解,同时 mapper 文件也不需要使用 parameterType 这个参数,Mybatis会 根据实体类(entity)的类型自动识别并匹配javaBean(这一部分在 spring配置文件关于数据源那一部分)
package com.ljq.cs.dao;
/**
* @description: 商品信息 DAO 接口
* @author: lujunqiang
* @email: [email protected]
* @date: 2017/12/17
*/
@Repository
public interface CommodityDao {
// 查询某一件商品
Commodity queryOne(Commodity commodity);
// 省略其他方法
}
2.传递单个参数,使用@Param注解
当使用javaBean作为对象的时候,在写 SQL 语句的时候,必须指定参数类型 parameterType="com.ljq.cs.entity.Commodity",同时在 #{ } 取值的时候不能直接填入 javaBean 的属性,必须这样使用 commodity.id ;否则,会抛出参数类型不匹配异常
如果不是 javaBean,则需要在写 SQL 语句的时候, #{ } 中的属性必须与 @Param中定义的一致,eg: @Param("username") , #{username} ,这样才可以
package com.ljq.cs.dao;
/**
* @description: 商品信息 DAO 接口
* @author: lujunqiang
* @email: [email protected]
* @date: 2017/12/17
*/
@Repository
public interface CommodityDao {
// 查询某一件商品
Commodity queryOne(@Param("commodity")Commodity commodity);
// 省略其他方法
}
3.传递多个参数,使用 @Param 注解
@Param 中定义的变量名必须和 mapper 中保持一致才可以
// 用户登录
UserInfo signin(@Param("account")String account,@Param("passcode")String passcode);
4.传递多个参数,不使用 @Param 注解
第一种场景中已经可以实现传递多个参数了,即把多个参数封装到一个 javaBean 中就可以实现了,但是如果是两个或者多个 javaBean 的时候,可以通过使用@Param注解的方式来实现,但是需要把每个 javaBean 中的属性全部拆分出来,这样就增加了巨大的代码量,因此不推荐这么做
UserInfo userInfo = new UserInfo();
Pagination page = new Pagination();
Map map = new HashMap<>;
map.put("userInfo",userInfo);
pam.put("page",page);
userService.searchUser(map);
@EnableCaching 启用缓存配置
@Cacheable
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的
参数 |
解释 |
example |
value |
缓存的名称,在 spring 配置文件中定义,必须指定至少一个 |
例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
key |
缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 |
@Cacheable(value=”testcache”,key=”#userName”) |
condition |
缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 |
@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。
@Conditional 注解是 Spring 4.0 之后出的一个注解,注解会根据具体的条件决定是否创建 bean 到容器中 ,条件注解的解析一定发生在spring ioc的bean definition阶段,ioc过程中,在component和enableautoconfiguration后还会调用ConfigurationClassParser processConfigurationClass方法