一、Bean
1.1 Usage
- Bean
@Data
@AllArgsConstructor
public class Car {
private String name;
private double price;
}
- Conf
@Configuration
public class AppConfiguration {
@Bean
public Car getCar() {
return new Car("Tesla", 1.0);
}
}
- Test
@SpringBootTest
public class CarTest {
@Autowired
private Car car;
@Test
public void testCreateCar() {
assertEquals("Tesla", car.getName());
assertEquals(1.0, car.getPrice());
}
}
1.2 With @PostConstruct & @PreDestroy
- Bean
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class Car {
private String name;
private double price;
public void init() {
log.info("Bean's init method invoked, Object has been created : " + name);
}
// @PostConstruct
// public void postConstruct() { ... }
public void destroy() {
log.info("Bean's destroy method invoked, Object has not been recycled : " + name);
}
// @PreDestroy
// public void preDestroy() { ... }
}
- Conf
@Configuration
public class AppConfiguration {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car getCar() {
return new Car("Tesla", 1.0);
}
}
- Test
@SpringBootTest
@Slf4j
public class CarTest {
@Autowired
private Car car;
@Test
public void testCreateCar() {
log.info("Test run ...");
}
}
- Output
Created after Spring Context initialized, destroyed before Spring Context exits.
... Car : Bean's init method invoked, Object has been created : Car(name=Tesla, price=1.0)
... CarTest : Started CarTest in 4.566 seconds (JVM running for 8.049)
... CarTest : Test run ...
... Car : Bean's destroy method invoked, Object has not been recycled : Car(name=Tesla, price=1.0)
1.3 With @Qualifier & @Resource
- Bean
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private String name;
private double price;
}
- Configuration
@Configuration
public class AppConfiguration {
// !!! Auto set bean name as method name
@Bean
public Car normalCar() {
return new Car("Create bean by method", 1.0);
}
@Bean("c1")
// @Bean({"c1", "c2"})
// @Bean(name = {"c1", "c2"})
public Car namedCar() {
return new Car("Create bean with name", 2.0);
}
}
- Test
@SpringBootTest
public class CarTest {
@Autowired
private Car normalCar; // !!! must same with method name
@Autowired
private Car c1; // !!! must same with annotated name
// @Autowired
// @Qualifier("c1")
// private Car someCar; // combine with @Qualifier to designate name of bean
@Resource(name = "c1")
private Car someCar; // else u can specify bean name with @Resource
@Test
public void testCreateCar() {
assertEquals("Create bean by method", normalCar.getName());
assertEquals("Create bean with name", c1.getName());
assertEquals("Create bean with name", someCar.getName());
}
}
1.4 With @Scope
Full list of scope reference in Spring website.
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance for each Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext. |
session | Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext. |
application | Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext. |
websocket | Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext. |
- Bean
@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class Car {
private String name;
private double price;
public void init() {
log.info("Bean's init method invoked, Object has been created : " + name);
}
public void destroy() {
log.info("Bean's destroy method invoked, Object has not been recycled : " + name);
}
}
- Conf
@Configuration
public class AppConfiguration {
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car getCar() {
return new Car("Tesla", 1.0);
}
}
- Test
@SpringBootTest
@Slf4j
public class CarTest {
@Autowired
private Car c1;
@Autowired
private Car c2;
@Test
public void testCreateCar() {
log.info("Test run ...");
}
}
- Output
Created every time before invoking and will be not destroyed automatically.
... CarTest : Started CarTest in 4.194 seconds (JVM running for 6.333)
... Car : Bean's init method invoked, Object has been created : Car(name=Tesla, price=1.0)
... Car : Bean's init method invoked, Object has been created : Car(name=Tesla, price=1.0)
... CarTest : Test run ...
1.5 With @Primary
- Conf
@Configuration
public class AppConfiguration {
@Bean
public Car normalCar() {
return new Car("Normal", 1.0);
}
@Primary
@Bean
public Car primaryCar() {
return new Car("Primary", 2.0);
}
}
- Test
Autowired
always links toPrimary
, specify bean’s name withResource
to break it.
@SpringBootTest
public class CarTest {
@Autowired
private Car normalCar;
@Autowired
private Car primaryCar;
@Resource(name = "normalCar")
private Car realNormalCar;
@Test
public void testCreateCar() {
assertEquals("Primary", normalCar.getName());
assertEquals("Primary", primaryCar.getName());
assertEquals("Normal", realNormalCar.getName());
}
}
1.6 With @Profile
- Conf
@Configuration
public class AbroadConf {
@Bean
@Profile("abroad")
public Car getCar() {
return new Car("Tesla", 2.0);
}
}
@Configuration
public class DomesticConf {
@Bean
@Profile("domestic")
public Car getCar() {
return new Car("Geely", 1.0);
}
}
- Property
spring:
profiles:
active: domestic
- Test
@SpringBootTest
public class CarTest {
@Autowired
private Car car;
@Test
public void testCar() {
assertEquals("Geely", car.getName());
assertEquals(1.0, car.getPrice());
}
}
1.7 With @DependsOn
- Bean
@Data
@AllArgsConstructor
@Slf4j
public class Car {
private String name;
private double price;
public void init() {
log.info("Car init : " + toString());
}
}
@Data
@AllArgsConstructor
@Slf4j
public class Wheel {
private String name;
private double price;
public void init() {
log.info("Wheel init : " + toString());
}
}
- Conf
@Configuration
public class AppConf {
@Bean(initMethod = "init")
@DependsOn(value = {"FrontWheel", "RearWheel"})
public Car getCar() {
return new Car("Tesla", 1.0);
}
@Bean(name = "FrontWheel", initMethod = "init")
public Wheel getFrontWheel() {
return new Wheel("FrontWheel", 2.0);
}
@Bean(name = "RearWheel", initMethod = "init")
public Wheel getRearWheel() {
return new Wheel("RearWheel", 3.0);
}
}
- Test
@SpringBootTest
@Slf4j
public class CarTest {
@Autowired
private Car car;
@Test
public void testCreateCar() {
log.info("Test run ... ");
}
}
- Output
... Wheel : Wheel init : Wheel(name=FrontWheel, price=2.0)
... Wheel : Wheel init : Wheel(name=RearWheel, price=3.0)
... Car : Car init : Car(name=Tesla, price=1.0)
... CarTest : Started CarTest in 4.309 seconds (JVM running for 8.102)
... CarTest : Test run ...
二、Request
@RestController
public class ParamController {
@GetMapping("/car/{id}/owner/{name}")
public Map<String,Object> getCar(@PathVariable Integer id,
@PathVariable String name,
@PathVariable Map<String,String> pathVars,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String,String> headers,
@RequestParam("age") Integer age,
@RequestParam("hobbies") List<String>hobbies,
@RequestParam Map<String,String> queries) {
Map<String,Object> map = new HashMap<>();
map.put("id",id);
map.put("name",name);
map.put("pathVars",pathVars);
map.put("userAgent",userAgent);
map.put("headers",headers);
map.put("age",age);
map.put("hobbies",hobbies);
map.put("queries",queries);
return map;
}
}
http://localhost:8080/car/1997/owner/rayslee?age=18&hobbies=jog&hobbies=swim
{
"id": 1997,
"name": "rayslee",
"pathVars": {
"id": "1997",
"name": "rayslee"
},
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
"headers": {
"host": "localhost:8080",
"connection": "keep-alive",
"cache-control": "max-age=0",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"sec-fetch-site": "none",
"sec-fetch-mode": "navigate",
"sec-fetch-user": "?1",
"sec-fetch-dest": "document",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh-CN,zh;q=0.9"
},
"age": 18,
"hobbies": [
"jog",
"swim"
],
"queries": {
"age": "18",
"hobbies": "jog"
}
}
2.1 @RequestParam
// 未指定参数名称时,变量必须与参数名相同
String getFoos(@RequestParam String id);
// 标识参数为非必填
String getFoos(@RequestParam(required = false) String id);
String getFoos(@RequestParam Optional<String> id);
// 为参数设置默认值
String getFoos(@RequestParam(defaultValue = "test") String id)
// 列表传参
// http://localhost:8080/spring-mvc-basics/api/foos?id=1,2,3
// http://localhost:8080/spring-mvc-basics/api/foos?id=1&id=2
2.2 @RequestBody
@RestController
public class ParamController {
@PostMapping("/save-car")
public Map<String,Object> saveCar(@RequestBody String body) {
Map<String,Object> map = new HashMap<>();
map.put("body", body);
return map;
}
// 也可以直接将使用类
// public Map<String,Object> saveCar(@RequestBody Car car)
}
2.3 @RequestAttribute
取出请求域中参数的值。
@Controller
public class RequestController {
@GetMapping("/goto")
public String goToPage(HttpServletRequest request) {
request.setAttribute("code", 200);
request.setAttribute("msg", "Congratulations");
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map<String,String> successPage(@RequestAttribute("code") Integer annotationCode,
@RequestAttribute("msg") String annotationMsg,
HttpServletRequest request) {
Map<String,String> map = new HashMap<>();
map.put("annotationCode", annotationCode.toString()); // 200
map.put("annotationMsg", annotationMsg); // Congratulations
map.put("requestCode", request.getAttribute("code").toString()); // 200
map.put("requestMsg", request.getAttribute("msg").toString()); // Congratulations
return map;
}
}
三、Conditional
3.1 @ConditionalOnClass/ MissingClass
这两个注解属于类条件注解,它们根据是否存在某个类作为判断依据来决定是否要执行某些配置。
@Configuration
@ConditionalOnClass(DataSource.class)
class MySQLAutoConfiguration {
//...
}
3.2 @ConditionalOnBean/ MissingBean
这两个注解属于对象条件注解,根据是否存在某个对象作为依据来决定是否要执行某些配置方法。
@Bean
@ConditionalOnBean(name="dataSource")
LocalContainerEntityManagerFactoryBean entityManagerFactory() {
// ...
}
@Bean
@ConditionalOnMissingBean
public MyBean myBean() {
// ...
}
3.3 @ConditionalOnProperty
根据Spring配置文件中的配置项是否满足配置要求,从而决定是否要执行被其标注的方法。
@Bean
@ConditionalOnProperty(name="alipay", havingValue="on")
public Alipay alipay() {
return new Alipay();
}
3.4 @ConditionalOnResource
用于检测当某个配置文件存在使,则触发被其标注的方法。
@ConditionalOnResource(resources = "classpath:website.properties")
Properties addWebsiteProperties() {
//...
}
3.5 @ConditionalExpression
更细粒度的基于表达式的配置条件限制,当表达式满足某个条件或者表达式为真的时候,将会执行被此注解标注的方法。
@Bean
@ConditionalException("${localstore} && ${local == 'true'}")
LocalFileStore store() {
// ...
}
3.6 @Conditional
控制更为复杂的配置条件。在Spring内置的条件控制注解不满足应用需求的时候,可以使用此注解定义自定义的控制条件,以达到自定义的要求。
@Conditioanl(CustomConditioanl.class)
CustomProperties addCustomProperties(){
//...
}
四、Transaction
4.1 TransactionDefinition.PROPAGATION_XXX
行为 | 说明 |
---|---|
PROPAGATION_REQUIRED | (默认值)如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 |
PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常。 |
PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。 |