Spring 注解

一、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.

ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototypeScopes a single bean definition to any number of object instances.
requestScopes 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.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes 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 to Primary, specify bean’s name with Resource 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

参考:https://mp.weixin.qq.com/s/8J9cafQdhJAu5hxjA20gKQ

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。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值