自带注解
@ModelAttribute
作用在接口方法或接口参数上
在接口方法上时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @ModelAttribute public void populateModel(ModelMap model) { model.addAttribute("attributeName", "123"); }
@ModelAttribute public User addUser() { User user = new User(); return user; }
@ModelAttribute("aaaa") public User addUser() { User user = new User(); return user; }
@ModelAttribute("string1-key") public String addString() { return "string1-value"; }
|
参数中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@RequestMapping(value = "helloWorld") public String helloWorld(@ModelAttribute("abc") User user, @ModelAttribute("attributeName") String aName, @ModelAttribute("string1-value") String svalue) { return "helloWorld"; }
@RequestMapping(value = "helloWorld2") public String helloWorld2(@ModelAttribute("user") User user) { System.out.println("---helloWorld---"+user.getUsername()+", "+user.getPassword()); return "helloWorld"; }
|
对比RequestParam、RequestBody
1 2 3
| 1. application/x-www-form-urlencoded,这种情况的数据@RequestParam、@ModelAttribute可以处理,@RequestBody也可以处理。 2. multipart/form-data,@RequestBody不能处理这种格式的数据。(form表单里面有文件上传时,必须要指定enctype属性值为multipart/form-data,意思是以二进制流的形式传输文件。) 3. application/json、application/xml等格式的数据,必须使用@RequestBody来处理。
|
@Order(n):bean的加载顺序
@EnableAsync:开启异步(多线程)
@Async:异步
可以注解在类或方法上,但不能是 static 修改
异步使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Async public void dealNoReturnTask() { logger.info("返回值为void的异步调用开始" + Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("返回值为void的异步调用结束" + Thread.currentThread().getName()); }
@Async public Future<String> dealHaveReturnTask(int i) { logger.info("asyncInvokeReturnFuture, parementer=" + i); Future<String> future; try { Thread.sleep(1000 * i); future = new AsyncResult<String>("success:" + i); } catch (InterruptedException e) { future = new AsyncResult<String>("error"); } return future; }
|
判断是否执行结束
1 2
| Future<String> f = Future<String>(1); f.isDone()
|
@Converter(autoApply = true)
Spring data jpa 中的实体属性转换器
@EnableScheduling:启动定时任务
@Scheduled:定时任务注解
在方法上添加@Scheduled
就可以定时执行了。
@Scheduled(fixedRate = 5000)
:上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay = 5000)
:上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000)
:第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="*/5 * * * * *")
:通过cron表达式定义规则
推荐
在线cron表达式网址
@EnableConfigurationProperties:读入自动配置类
比如
1
| @ConfigurationProperties(prefix = "spring.datasource")
|
@ConditionalOnClass:加载自动配置类
1 2 3 4 5 6
| @Configuration //配置类 //这里就是前面说的,这个注解读入我们的配置对象类 @EnableConfigurationProperties(HelloProperties.class) //当类路径存在这个类时才会加载这个配置类,否则跳过,这个很有用比如不同jar包间类依赖,依赖的类不存在直接跳过,不会报错 @ConditionalOnClass(HelloService.class) // HelloService 类上不需要加 Component
|
@EnableAutoConfiguration
不要自己添加
@Primary 优先选择
@Configuration 把一个类作为一个IoC容器
它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件
如struts中的action)
@Repository 标注数据访问组件
即DAO组件。
@Component 组件<泛指>,当组件不好归类的时候
@PostConstruct 用于指定初始化方法(用在方法上)
@PreDestory 用于指定销毁方法(用在方法上)
@Resource 默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
@ConditionalOnMissingBean
当前bean 不存在时,使用备用bean
1 2 3 4 5 6 7 8 9 10 11
| @Configuration @ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic {
@Bean public DataSource dataSource(DataSourceProperties properties) { return properties.initializeDataSourceBuilder().build(); }
}
|
@Value
1 2
| @Value(value = "${snowflake.data_center_id}") private long dataCenterId = -1L;
|
@ConfigurationProperties(prefix = “”)
自定义配置类, prefix
为前缀.
比如 DataSourceProperties
类
1 2 3 4 5 6 7
| @ConfigurationProperties(prefix = "spring.datasource") public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean { private String driverClassName; private String url; private String username; private String password; }
|
对于下面的配置,上面会自动注入
1 2 3 4 5 6
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: root
|
@NestedConfigurationProperty
使用于 @ConfigurationProperties(prefix = "")
中, 主要是为了嵌套配置, 比如当前配置中有 Map
、List
、class
等类型的属性时,需要用 @NestedConfigurationProperty
标记。
用来指示应该将常规(非内部)类视为嵌套类。
比如 MybatisPlusProperties
:
1 2 3 4 5 6 7
| @ConfigurationProperties(prefix = Constants.MYBATIS_PLUS) public class MybatisPlusProperties { @NestedConfigurationProperty private MybatisConfiguration configuration; @NestedConfigurationProperty private GlobalConfig globalConfig = GlobalConfigUtils.defaults(); }
|
自定义注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。
@Target:
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Target(ElementType.TYPE) public @interface Table { /** * 数据表名称注解,默认值为类名称 * @return */ public String tableName() default "className"; }
@Target(ElementType.FIELD) public @interface NoDBColumn {
}
|
注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。
@Retention:
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:
1 2 3 4 5 6 7 8
| @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { public String name() default "fieldName"; public String setFuncName() default "setField"; public String getFuncName() default "getField"; public boolean defaultDBValue() default false; }
|
Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理
@Documented:
**@**Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
1 2 3 4 5 6 7 8 9
| @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Column { public String name() default "fieldName"; public String setFuncName() default "setField"; public String getFuncName() default "getField"; public boolean defaultDBValue() default false; }
|
@Inherited:
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
实例代码:
1 2 3 4 5 6 7 8 9 10 11
| /** * * @author peida * */ @Inherited public @interface Greeting { public enum FontColor{ BULE,RED,GREEN}; String name(); FontColor fontColor() default FontColor.GREEN; }
|
自定义注解:
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
定义注解格式:
public @interface 注解名 {定义体}
注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第三,如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
简单的自定义注解和使用注解实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package annotation;
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
/** * 水果名称注解 * @author peida * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitName { String value() default ""; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package annotation;
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
/** * 水果颜色注解 * @author peida * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FruitColor { /** * 颜色枚举 * @author peida * */ public enum Color{ BULE,RED,GREEN}; /** * 颜色属性 * @return */ Color fruitColor() default Color.GREEN;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package annotation;
import annotation.FruitColor.Color;
public class Apple { @FruitName("Apple") private String appleName; @FruitColor(fruitColor=Color.RED) private String appleColor; public void setAppleColor(String appleColor) { this.appleColor = appleColor; } public String getAppleColor() { return appleColor; } public void setAppleName(String appleName) { this.appleName = appleName; } public String getAppleName() { return appleName; } public void displayName(){ System.out.println("水果的名字是:苹果"); } }
|
1 2 3 4 5
| @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserAccess { String desc() default "无信息"; }
|
用反射机制来调用注解中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.dragon.test.annotation;
import java.lang.annotation.Annotation; import java.lang.reflect.Method;
/** * 用反射机制来调用注解中的内容 * Created by gmq on 2015/9/10. */ public class MyReflection { public static void main(String[] args) throws Exception { // 获得要调用的类 Class<MyTest> myTestClass = MyTest.class; // 获得要调用的方法,output是要调用的方法名字,new Class[]{}为所需要的参数。空则不是这种 Method method = myTestClass.getMethod("output", new Class[]{}); // 是否有类型为MyAnnotation的注解 if (method.isAnnotationPresent(MyAnnotation.class)) { // 获得注解 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); // 调用注解的内容 System.out.println(annotation.hello()); System.out.println(annotation.world()); } System.out.println("----------------------------------"); // 获得所有注解。必须是runtime类型的 Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations) { // 遍历所有注解的名字 System.out.println(annotation.annotationType().getName()); } } }
|
自定义注解还可以放入AOP
注解 @UserAccess
1 2 3 4 5
| @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface UserAccess { String desc() default "无信息"; }
|
AOP 中的使用
1 2 3 4
| @After("@annotation(userAccess)") public void after(JoinPoint jp, UserAccess userAccess) { log.debug("second after:" + userAccess.desc()); }
|
本文地址: https://github.com/maxzhao-it/blog/post/44534/