springboot注解解析
springboot注解
启动类入口程序—启动注解@SpringBootApplication
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableTransactionManagement
public class PlatsystemApplication {
这是一个复合注解,它包含了@ComponentScan
,和@SpringBootConfiguration
,@EnableAutoConfiguration
等注解。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@SpringBootConfiguration
继承自@Configuration
,二者功能也一致,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean
注解标记的方法的实例纳入到srping
容器中,并且实例名就是方法名。@EnableAutoConfiguration
的作用启动自动的配置,@EnableAutoConfiguration
注解的意思就是Springboot
根据你添加的jar包来配置你项目的默认配置,比如根据spring-boot-starter-web
,来判断你的项目是否需要添加了webmvc
和tomcat
,就会自动的帮你配置web项目中所需要的默认配置。在下面博客会具体分析这个注解,快速入门的demo实际没有用到该注解。@ComponentScan
,扫描当前包及其子包下被@Component
,@Controller
,@Service
,@Repository
注解标记的类并纳入到spring容器中进行管理。是以前的<context:component-scan>
(以前使用在xml中使用的标签,用来扫描包配置的平行支持)。所以本demo中的User为何会被spring
容器管理。
@SpringBootApplication参数:
- Class<?>[] exclude() default {}:
根据class来排除,排除特定的类加入spring容器,传入参数value类型是class类型。 - String[] excludeName() default {}:
根据class name来排除,排除特定的类加入spring容器,传入参数value类型是class的全类名字符串数组。 - String[] scanBasePackages() default {}:
指定扫描包,参数是包名的字符串数组。 - Class<?>[] scanBasePackageClasses() default {}:
扫描特定的包,参数类似是Class类型数组。
配置类相关注解
@Configuration
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源(一般配合@Bean注解使用)。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。最简单可行的 @Configuration 类如下所示:
package org.wzh.di.demo1.congiration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HelloWorldConfig {
@Bean
public HelloWorld helloWorld() {
return new HelloWorld();
}
}
因为@Configuration本身也是一个@Component,因此配置类本身也会被注册到应用上下文,并且也可以使用IOC的@Autowired@Inject等注解来注入所需bean。
使用外部数据
在配置类中,可以通过注入环境和配置相关参数对象,之后再构建Bean时,可以使用这些外部数据。
//在配置类中,从环境变量获取数据并传递到Bean中
@Configuration
public class AppConfig {
@Autowired
public Environment env;
@Bean
IBean appBean(){
AppBean appBean = new AppBean();
appBean.setName(env.getProperty("xxx"));//此处xxx需要替换成环境中存在的值
return appBean;
}
}
@Configuration组合使用
//新建一个配置类,例如数据库配置类:
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource(){
return new DataSource(){...};
}
}
//然后在AppConfig中用@Import来导入配置类
@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
@Autowired
public DataSource dataSource; //注入的bean在DatabaseConfig.class中定义
@Bean
IBean appBean(){
return new AppBean();
}
}
同@Profile注解组合使用
在配置类中可以申明@Profile注解,仅当满足profile条件时,才会处理配置类,也可以将@Profile注解加载配置类中的每一个@Bean来实现更细粒度的条件控制。(@Profile 注解的作用在不同的场景下,给出不同的类实例。比如在生产环境中给出的 DataSource 实例和测试环境给出的 DataSource 实例是不同的。)
@Configuration
@Profile("develop")
public class DatabaseConfig {
@Bean
public DataSource dataSource(){
return new DataSource(){...};
}
}
同@ImportReource注解组合使用
新建spring xml配置文件config_other_bean.xml
<beans>
<bean class="com.zhaolin81.spring.framework.config.annotation.otherconfig.DatabaseConfig"></bean>
</beans>
修改配置类
@Configuration
@ImportResource("classpath:config_other_bean.xml")
public class AppConfig {
@Autowired
public DataSource dataSource; //注入的bean在config_other_bean.xml中定义
@Bean
IBean appBean(){
return new AppBean();
}
}
组件添加
@Component
把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>。
@Component
泛指组件,当组件不好归类的时候(不属于@Controller、@Services等的时候),我们可以使用这个注解进行标注。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
default
参数用来指定bean的名称,若不指定,则以类名首字母小写
为默认bean的名称
不指定名称:
@Component
public class IncomeMonDBService {
bean名称为incomeMonDBService
,可以通过ApplicationContext.getBean("incomeMonDBService")或ApplicationContext.getBean(IncomeMonDBService.class)从spring容器中拿到对应实例。
指定名称:
@Component("incService")
public class IncomeMonDBService {
bean的名称为incService
。
@controller
用于标注控制层组件(注入服务)
@Controller
@RequestMapping("/invcomp")
public class InvCompController extends AbstractCommonController {
@service
用于标注业务层组件,进行业务的逻辑处理
@Service
@Lazy
public class InsertCompInfoImpl implements IService {
@repository
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件,实现dao访问
@Scope
以上组件注解默认都是单例模式,即scope="singleton"。另外scope还有prototype、request、session、global session作用域。
@Service
@Scope("prototype")
@Lazy
public class InsertCompInfoImpl implements IService {
若想更改bean的作用域,可以使用@Scope注解
1.singleton单例模式,
全局有且仅有一个实例
2.prototype原型模式,
每次获取Bean的时候会有一个新的实例
3.request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
4.session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
5.global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用
@Lazy
用于标识bean是否需要延迟加载。
ApplicationContext实现的默认行为就是在启动服务器时将所有singleton bean提前进行实例化
(也就是依赖注入)。提前实例化意味着作为初始化过程的一部分,applicationContext实例会创
建并配置所有的singleton bean。通常情况下这是一件好事,因为这样在配置中的任何错误就会
被立刻实现(否则的话可能要话几个小时甚至几天)。
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
boolean value() default true;
}
只有一个参数,默认是true,也就是说只要加了这个注解,bean将不会在ApplicationContext启动时提前被实例化,而是第一次向容器通过getBean索取bean时实例化的。
注意:
如果一个设置了立即加载的bean1,引用了一个延时加载的bean2,那么bean1在容器启动时被实例化,而bean2
由于被bean1引用,所以也被实例化,这种情况也符合延时加载的bean在第一次调用时才被实例化的规则。
如果@Configuration 上使用了Lazy,则@Configuration 中的所有都会被懒加载。
除了作用于@Component组件或其@Bean初始化方法,也作用于Inject和Autowired。就是Autowired注释的bean会默认进行懒加载,除非他之前就被加载了。
@Bean
@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
@bean 也可以依赖其他任意数量的bean,如果TransferService 依赖 AccountRepository,我们可以通过方法参数实现这个依赖
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
任何使用@Bean定义的bean,也可以执行生命周期的回调函数,类似@PostConstruct and @PreDestroy的方法。用法如下
public class Foo {
public void init() {
// initialization logic
}
}
public class Bar {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public Foo foo() {
return new Foo();
}
@Bean(destroyMethod = "cleanup")
public Bar bar() {
return new Bar();
}
}
默认使用javaConfig配置的bean,如果存在close或者shutdown方法,则在bean销毁时会自动执行该方法,如果你不想执行该方法,则添加@Bean(destroyMethod="")来防止出发销毁方法
@Autowired
@Autowired可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。
@Component
public class InvoiceOperationUtil {
}
@Service
@Lazy
public class InvalidInvoiceImpl implements IService {
private static Logger logger = LoggerFactory.getLogger(InvalidInvoiceImpl.class);
@Autowired
private InvoiceOperationUtil invoiceOperationUtil;
}
InvalidInvoiceImpl实现类有一个InvoiceOperationUtil类型的属性,通过@Autowired自动装配方式,从IoC容器中去查找到,并返回给该属性。
其实在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性
注意事项:
在使用@Autowired时,首先在容器中查询对应类型的bean
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
如果查询的结果不止一个,那么@Autowired会根据属性名称来查找。
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
JSR-250规范定义的注解
@Resource、@PostConstruct以及@PreDestroy
@PostConstruct相当于init-method,使用在方法上,当Bean初始化时执行。
@PreDestroy相当于destory-method,使用在方法上,当Bean销毁时执行。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName
自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性
解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策
略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
-
如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
-
如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
-
如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
-
如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个
原始类型进行匹配,如果匹配则自动装配;
@Autowired 与@Resource的区别:
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要
允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配
可以结合@Qualifier注解进行使用,如下:
`@Autowired``()``@Qualifier``(``"baseDao"``)``private``BaseDao baseDao;`
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有
指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性
名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指
定,就只会按照名称进行装配。
`@Resource``(name=``"baseDao"``)``private``BaseDao baseDao;`
@Qualifier
一般作为@Autowired()的修饰用
@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个UserDao类型的bean时,就会抛
出BeanCreationException异常;如果Spring上下文中不存在UserDao类型的bean,也会抛出
BeanCreationException异常。我们可以使用@Qualifier配合@Autowired来解决这些问题。如下:
①可能存在多个UserDao实例
@Autowired
@Qualifier("userServiceImpl")
public IUserService userService;
或者
@Autowired
public void setUserDao(@Qualifier("userDao") UserDao userDao) {
this.userDao = userDao;
}
这样Spring会找到id为userServiceImpl和userDao的bean进行装配。
配置文件相关注解
@ConfigurationProperties
想要读取配置文件的信息并自动封装成实体类,可以使用@ConfigurationProperties,它可以把同类的配置信息自动封装成实体类
首先在配置文件里面,这些信息是这样子的:
connection.username=admin
connection.password=kyjufskifas2jsfs
connection.remoteAddress=192.168.1.1
这时候可以定义一个实体类在装载配置文件信息
@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionSettings {
private String username;
private String remoteAddress;
private String password ;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRemoteAddress() {
return remoteAddress;
}
public void setRemoteAddress(String remoteAddress) {
this.remoteAddress = remoteAddress;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
还可以把@ConfigurationProperties还可以直接定义在@bean的注解上,这是bean实体类就不用@Component和@ConfigurationProperties了
@SpringBootApplication
public class DemoApplication{
//...
@Bean
@ConfigurationProperties(prefix = "connection")
public ConnectionSettings connectionSettings(){
return new ConnectionSettings();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
如果发现@ConfigurationPropertie不生效,有可能是项目的目录结构问题,
可以通过@EnableConfigurationProperties(ConnectionSettings.class)来明确指定需要用哪个实体类来装载配置信息
@Configuration
@EnableConfigurationProperties(ConnectionSettings.class)
public class MailConfiguration {
@Autowired private MailProperties mailProperties;
@Bean public JavaMailSender javaMailSender() {
// omitted for readability
}
}
@PropertySource
加载指定的配置文件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
/**
* 资源的名称
*/
String name() default "";
/**
* 资源文件路径,可以是数据多个文件地址
* 可以是classpath地址如:
* "classpath:/com/myco/app.properties"
* 也可以是对应的文件系统地址如:
* "file:/path/to/file"
*/
String[] value();
/**
* 是否忽略文件资源是否存在,默认是false,也就是说配置不存在的文件地址spring启动将会报错
*/
boolean ignoreResourceNotFound() default false;
/**
* 这个没什么好说的了就是对应的字符编码了,默认是空值,如果配置文件中有中文应该设置为utf-8 */
String encoding() default "";
/**
* 关键的元素了 读取对应资源文件的工厂类了 默认的是PropertySourceFactory
*/
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}
例子:
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
* prefix = "person":配置文件中哪个下面的所有属性进行一一映射
*
* @ConfigurationProperties(prefix = "person")默认从全局配置文件中获取值;
*
*/
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
}
通过Environment设置
@Configuration
@PropertySource("classpath:jdbc.properties")
public class PropertiesWithJavaConfig {
@Autowired
private Environment env;
}
接着就可以用env.getProperty("jdbc.driver")得到相应的属性值
Mybatis-数据源相关注解
@MapperScan
用@MapperScan注解,指定basePackages,扫描mybatis Mapper接口类
@Configuration
@MapperScan(basePackages = {"com.lqt.db2dao.mapper"}, sqlSessionFactoryRef = "db2SqlSessionFactory")
public class Db2DatasourceConfig {
@Transactional
事务管理
@Transactional(value = "db2TransactionManager", rollbackFor = Exception.class)
public Map<String, Object> insertdbOperate(InvGoodsInfo goodsInfo, InvGoodsReln goodsReln) throws DataAccessException {
}
要启用声明式事务,还得在启动类上添加@EnableTransactionManagement注解
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableTransactionManagement
public class PlatsystemApplication {
public static void main(String[] args) {
SpringApplication.run(PlatsystemApplication.class, args);
}
}
@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 | 不会导致事务回滚的异常类名字数组 |
用法
由Spring来统一管理业务对象,这样业务对象上面的事务才会生效。
如果业务对象是通过new产生的,即没有注册bean,数据库是不会执行回滚的。
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为Spring数据库事务的约定,其实现原理是AOP,而AOP的原理是动态代理,只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。
要解决这个问题,可以用一个service去调用另一个service,这样就是代理对象的调用;也可以从Spring IOC容器中获取代理对象去启动AOP。
spring事务回滚规则
指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。
还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。
@Primary
当一个接口有2个不同实现时,使用@Autowired注解时会报org.springframework.beans.factory.NoUniqueBeanDefinitionException异常信息
Primary可以理解为默认优先选择,同时不可以同时设置多个
另外,在配置多数据源是,一定要配置在其中一个数据源上加上@Primary注解。
测试相关注解
@RunWith
当一个类用@RunWith注释或继承一个用@RunWith注释的类时,JUnit将调用它所引用的类来运行该类中的测试而不是开发者去在junit内部去构建它。
@RunWith就是一个运行器
@RunWith(JUnit4.class)就是指用JUnit4来运行
@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境
@RunWith(SpringRunner.class)(SpringRunner 继承了SpringJUnit4ClassRunner,没有扩展任何功能;使用SpringRunner,名字简短而已。)
@RunWith(Suite.class)的话就是一套测试集合
@ContextConfiguration Spring整合JUnit4测试时,使用注解引入多个配置文件
单个文件
@ContextConfiguration(Locations="classpath:applicationContext.xml")
@ContextConfiguration(classes = SimpleConfiguration.class)
多个文件时,可用
@ContextConfiguration(locations = { "classpath:spring1.xml", "classpath:spring2.xml" })
@SpringBootTest
使用@SpringBootTest注解可以运行环境,测试后台代码。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StartUpApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PlatsystemApplicationTests {
}
//其中,classes属性指定启动类,SpringBootTest.WebEnvironment.RANDOM_PORT经常和测试类中@LocalServerPort一起在注入属性时使用。会随机生成一个端口号。
springboot单元测试关节注解接受
-
@RunWith(SpringJUnit4ClassRunner.class),这是JUnit的注解,通过这个注解让SpringJUnit4ClassRunner这个类提供Spring测试上下文。
-
@SpringApplicationConfiguration(classes = 启动类.class),这是Spring Boot注解,为了进行集成测试,需要通过这个注解加载和配置Spring应用上下文。这是一个元注解(meta-annoation),它包含了@ContextConfiguration( loader = SpringApplicationContextLoader.class)这个注解,测试框架通过这个注解使用Spring Boot框架的SpringApplicationContextLoader加载器创建应用上下文。
-
@WebAppConfiguration 表明是WEB应用环境,不能和@WebIntegrationTest一起使用
-
@WebIntegrationTest(“server.port:0”),这个注解表示当前的测试是集成测试(integration test),因此需要初始化完整的上下文并启动应用程序。这个注解一般和@SpringApplicationConfiguration一起出现。server.port:0指的是让Spring Boot在随机端口上启动Tomcat服务,随后在测试中程序通过@Value(“${local.server.port}”)获得这个端口号,并赋值给port变量。当在Jenkins或其他持续集成服务器上运行测试程序时,这种随机获取端口的能力可以提供测试程序的并行性。
-
@SpringBootTest(classes = AppApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK) 指定启动类,web环境
- WebEnvironment.MOCK—提供一个Mock的Servlet环境,内置的Servlet容器并没有真实的启动,主要搭配使用@AutoConfigureMockMvc
- WebEnvironment.RANDOM_PORT — 提供一个真实的Servlet环境,也就是说会启动内置容器,然后使用的是随机端口
- WebEnvironment.DEFINED_PORT — 这个配置也是提供一个真实的Servlet环境,使用的默认的端口,如果没有配置就是8080
- WebEnvironment.NONE — 这是个神奇的配置,跟Mock一样也不提供真实的Servlet环境。
JUnit相关注解
//在所有测试方法前执行一次,一般在其中写上整体初始化的代码
@BeforeClass
//在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码
@AfterClass
//在每个测试方法前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据)
@Before
//在每个测试方法后执行,在方法执行完成后要做的事情
@After
// 测试方法执行超过1000毫秒后算超时,测试将失败
@Test(timeout = 1000)
// 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败
@Test(expected = Exception.class)
// 执行测试时将忽略掉此方法,如果用于修饰类,则忽略整个类
@Ignore(“not ready yet”)
@Test
打包测试
正常情况下我们写了5个测试类,我们需要一个一个执行。 打包测试,就是新增一个类,然后将我们写好的其他测试类配置在一起,然后直接运行这个类就达到同时运行其他几个测试的目的。
@RunWith(Suite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {
// 类中不需要编写代码
}
多环境测试
@ActiveProfiles(profiles = "test")
//在测试类上面指定profiles,可以改变当前spring 的profile,来达到多环境的测试
MockMvc 模拟外部环境测试
@RunWith(SpringRunner.class.class)
@SpringBootTest(classes = AppApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class AppApplication{
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setupMockMvc() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
/***
* 测试添加用户接口
* @throws Exception
*/
@Test
public void testAddUser() throws Exception {
//构造添加的用户信息
UserInfo userInfo = new UserInfo();
userInfo.setName("testuser2");
userInfo.setAge(29);
userInfo.setAddress("北京");
ObjectMapper mapper = new ObjectMapper();
//调用接口,传入添加的用户参数
mockMvc.perform(post("/user/adduser")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(mapper.writeValueAsString(userInfo)))
//判断返回值,是否达到预期,测试示例中的返回值的结构如下{"errcode":0,"errmsg":"OK","p2pdata":null}
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
//使用jsonPath解析返回值,判断具体的内容
.andExpect(jsonPath("$.errcode", is(0)))
.andExpect(jsonPath("$.p2pdata", notNullValue()))
.andExpect(jsonPath("$.p2pdata.id", not(0)))
.andExpect(jsonPath("$.p2pdata.name", is("testuser2")));
}
}