Java 原生注解
注解(Annotation),元数据(Meta data)的一种形式,提供了程序本身之外的数据。是从jdk1.5才引入的特性,注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。
@PostConstruct
注解
该注解被用来修饰一个非静态的 void()
方法。被@PostConstruct
修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次,是在构造函数之后执行,init()
方法之前执行。
通常我们会是在Spring框架中使用到@PostConstruct
注解 该注解的方法在整个Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired或@Resource(依赖注入) -> @PostConstruct(注释的方法)
@Slf4j
@Component
public class ConfigConst {
@Resource
SysConfigRepository sysConfigDao;
@Resource
private RedisTemplate<String, String> redisTemplate;
//@Config 是自定义的一个配置缓存注记
@Config(key="huawei.obs")
public static String HUAWEI ;
//此组件Constructor构造函数执行完毕,所有其他组件加载完毕后执行此标注的init()方法
@PostConstruct
public void init(){
Iterable<SysConfig> iterator =sysConfigDao.findAll();
iterator.forEach(
sysConfig -> {
redisTemplate.opsForValue().set(sysConfig.getKey(), sysConfig.getValue());
}
);
Field[] fields = ConfigConst.class.getDeclaredFields();
List<Field> configFields =
Arrays.stream(fields).filter(field -> ObjectUtil.isNotNull(field.getAnnotation(Config.class)))
.collect(Collectors.toList());
for(Field field:configFields){
Config config = field.getAnnotation(Config.class);
if(ObjectUtil.isNotNull(redisTemplate.opsForValue().get(config.key()))){
log.warn(config.key()+"未配置");
}
ReflectUtil.setFieldValue(ConfigConst.class,field.getName()
,redisTemplate.opsForValue().get(config.key()));
}
}
}
Lombok 插件常用注解
@Data
注解
经常用 @Data 注解标记在实体类上面快速实现getters 和 setters, 而它好用地注解应该不至于这一个,下面是常用地注解汇总:
一般用在类上,提供类所有属性的 get 和 set 方法,此外还提供了equals、canEqual、hashCode、toString等方法;
@Setter
注解
一般用在属性上,为属性提供 set 方法, 用在再类上则表示当前类中所有属性都生成set方法;
@Getter
注解
用在属性上,为属性提供 get 方法, 用在再类上表示当前类中所有属性都生成get方法;
@NoArgsConstructor
注解
用在类上,为类提供一个无参的构造方法;
@AllArgsConstructor
注解
用在类上,为类提供一个全参的构造方法;
@RequiredArgsConstructor
注解
用在类上,生成一个包含 “特定参数” 的构造器,特定参数指的是那些有加上 final 修饰词的变量们;
@Builder
注解
用在类上,自动生成流式 set 值写法,从此之后再也不用写一堆 setter 了;
虽然只要加上@Builder注解,我们就能够用流式写法快速设定对象的值,但是 setter
还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对他们取值/赋值所以通常是 @Data 和 @Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事;
@Cleanup注解
可以用在 IO 流上,用于关闭并释放资源;
例如下面例子,每次IO六操作后要在finally中关闭流,释放资源:
public class CleanupExample {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
}
类似以上地一个IO留操作的方法使用lombok 的 @Cleanup 注解后可以简化成这样:
public class CleanupExample {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}
@SneakyThrows
注解
利用了这一机制,将当前方法抛出的异常,包装成RuntimeException,骗过编译器,使得调用点可以不用显示处理异常信息,使用注解后不需要担心Exception的处理。例如:
import lombok.SneakyThrows;
public class SneakyThrowsExample implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
真正生成的代码
import lombok.Lombok;
public class SneakyThrowsExample implements Runnable {
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw Lombok.sneakyThrow(e);
}
}
public void run() {
try {
throw new Throwable();
} catch (Throwable t) {
throw Lombok.sneakyThrow(t);
}
}
}
SpringBoot常用注解
@Bean
注解
用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
SpringIOC 容器管理一个或者多个bean,这些bean都需要在@Configuration注解下进行创建,在一个方法上使用@Bean注解就表明这个方法需要交给Spring进行管理。详细了解参考: @Bean 注解全解析 。
@ConditionalOnMissingBean
注解
是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfiguration {
/**
* Bean:定义一个customizer的方法并生成bean对象交给IOC
* ConditionalOnMissingBean: 保证此对象只注册一次,从夫注册同名同类的对象时抛出异常
**/
@Bean
@ConditionalOnMissingBean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return builder -> {
builder.locale(Locale.CHINA);
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
builder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
builder.serializerByType(Long.class, ToStringSerializer.instance);
builder.modules(new PigJavaTimeModule());
};
}
}
@AutoConfigureBefore
、@AutoConfigureAfte
r 和@Order
注解
用来控制@Configuration标记的配置文件加载顺序,具体参考: 链接
@Condition
类注解
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用,才会实例化一个Bean)
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。