当一个方法或者类已经弃用,新版本中将会有其他方法或者类可以代替这个使用,以后也不会再维护这个方法或类,就可以在方法的前面加上此注解,加上此注解方法名中间会如下图所示增加一条横线。
public class TestService {
public static void main(String[] args) {
new TestService().method();
}
/**
* Description: [do something]
* created: 2019年4月26日上午9:51:09
* @param:
* @return: void
* @throws
* {@link TestService}
链接替代类型或方法
*/
@Deprecated
public void method() {
System.out.println("这是一个过时的方法");
}
}
@Target用于声明注解可修饰的范围(即注解的使用范围),其注解中的ElementType属性可取以下值:
* ONSTRUCTOR:用于描述构造器
* FIELD:用于描述域
* METHOD:用于描述方法
* LOCAL_VARIABLE:用于描述局部变量
* PACKAGE:用于描述包
* PARAMETER:用于描述参数
* TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Target(ElementType.TYPE)
public @interface Table {
/**
* 数据表名称注解,默认值为类名称
*/
public String tableName() default "className";
}
@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
@Inherited 主要用于标记注解,被该注解标记过的注解,被认为是存在继承关系的。
即如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
标注要扫描的mapper接口的位置,在使用mybatis时,通常使用@Mapper或@Repository标注dao层接口,但每个接口都进行标注比较繁琐,使用@MapperScan可以替代这一繁琐过程,只需在basePackages属性中配置接口所在的包名,即可在启动项目时扫描注入该包下的所有接口。
// 可指定多个包
@MapperScan(basePackages = {"com.company.project.dao"})
另外,在使用@MapperScan注解时,需要注意引入的注解类是否正确,通常情况下使用org的@MapperScan,但项目中如果使用了通用Mapper,那则使用tk的@MapperScan。
import org.mybatis.spring.annotation.MapperScan;
import tk.mybatis.spring.annotation.MapperScan;
异步注解,标注的方法在调用时会单独创建一个线程去异步执行,下面贴上springboot中的简单使用示例:
首先配置一个线程池:
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ThreadPoolConfig {
@Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);//核心线程数
executor.setMaxPoolSize(200);//最大线程数
executor.setQueueCapacity(99999);//线程队列大小
executor.setThreadNamePrefix("thread-name:");//线程名前缀
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
然后在启动类中开启异步调用:
@MapperScan(basePackages = {"com.myproject.demo.dao"})
@SpringBootApplication
@EnableAsync //开启异步注解
public class MyprojectApplication {
public static void main(String[] args) {
SpringApplication.run(MyprojectApplication.class, args);
}
}
编写异步方法和测试方法
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class AsyncThreadUtil {
@Async // 如果不指定名字,会使用缺省的“asyncExecutor”
public void asyncTest(String name){
for (int i = 0; i < 5; i++) {
log.info(name + i);
try {
Thread.sleep(2L);
} catch (InterruptedException e) {
log.debug("sleep exception:{}", e.getMessage());
}
}
}
}
-------------------测试方法------------------------
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.myproject.demo.util.AsyncThreadUtil;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyprojectApplicationTests {
@Autowired
private AsyncThreadUtil asyncThreadUtil;
@Test
public void contextLoads() {
asyncThreadUtil.asyncTest(1 + "号张三");
asyncThreadUtil.asyncTest(2 + "号张三");
}
}
可以看到,在调用的异步方法开启了两个线程:thread-name:2、thread-name:1,并不是在主线程中处理的。
2019-04-28 11:40:40.346 INFO 6028 --- [ main] c.m.demo.MyprojectApplicationTests : Started MyprojectApplicationTests in 8.785 seconds (JVM running for 10.128)
2019-04-28 11:40:40.849 INFO 6028 --- [ thread-name:2] com.myproject.demo.util.AsyncThreadUtil : 2号张三0
2019-04-28 11:40:40.851 INFO 6028 --- [ thread-name:2] com.myproject.demo.util.AsyncThreadUtil : 2号张三1
2019-04-28 11:40:40.853 INFO 6028 --- [ thread-name:2] com.myproject.demo.util.AsyncThreadUtil : 2号张三2
2019-04-28 11:40:40.854 INFO 6028 --- [ thread-name:1] com.myproject.demo.util.AsyncThreadUtil : 1号张三0
2019-04-28 11:40:40.855 INFO 6028 --- [ thread-name:2] com.myproject.demo.util.AsyncThreadUtil : 2号张三3
2019-04-28 11:40:40.857 INFO 6028 --- [ thread-name:2] com.myproject.demo.util.AsyncThreadUtil : 2号张三4
2019-04-28 11:40:40.858 INFO 6028 --- [ thread-name:1] com.myproject.demo.util.AsyncThreadUtil : 1号张三1
2019-04-28 11:40:40.943 INFO 6028 --- [ thread-name:1] com.myproject.demo.util.AsyncThreadUtil : 1号张三2
2019-04-28 11:40:40.958 INFO 6028 --- [ thread-name:1] com.myproject.demo.util.AsyncThreadUtil : 1号张三3
2019-04-28 11:40:40.960 INFO 6028 --- [ thread-name:1] com.myproject.demo.util.AsyncThreadUtil : 1号张三4
更多@Async异步线程使用方法,可以看看这篇博客:Spring中@Async用法详解及简单实例
从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct和@PreDestroy,这两个注解被用来修饰一个非静态的void()方法。
被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
被@PreDestroy修饰的方法会在servlet执行destroy()方法执行之前执行。
@PostConstruct使用场景:
如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用,示例代码:
在这里插入代码片import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.myproject.demo.util.AsyncThreadUtil;
@Component
public class Demo {
private Integer demoNumber;
@Autowired
private AsyncThreadUtil asyncThreadUtil;
public Demo() {
//通过构造器去使用spring注入的属性是会失败的
//此处numberUtil为一个随意的bean,getNumber()获取 一个随机数,代码不贴了
this.demoNumber = numberUtil.getNumber();
}
public Integer getDemoNumber() {
return demoNumber;
}
// @PostConstruct
// private void InitNumber() {
// this.demoNumber = numberUtil.getNumber();
// }
}
----------------以下是测试代码-------------------
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class MyprojectApplicationTests {
@Autowired
private Demo demo;
@Test
public void test2() {
log.debug("demo number : {}", demo.getDemoNumber());
}
}
最终的结果当然是失败的,因为当调用构造器时,其被spring管理的属性,还没有注入,导致了空指针异常,但当我们将上述代码中构造器中的代码注释掉,然后将@PostConstruct方法释放出来,再次执行,即可成功,达到我们想要的目的。
最后可以总结出,spring注入bean时的顺序为:Constructor >> @Autowired >> @PostConstruct