Spring 注解学习
分类
- Spring的bean容器相关
@Required @Autowired @PostConstruct @PreDestory
@Inject @Named @Qualifer @Provider @Scope @Singleton
- springmvc 相关
@Controller @RequestMapping @RequestParam @ResponseBody 等
- 类注解
- @Component、@Repository、@Controller、@Service @ManagedBean和@Named
都是添加在类上面的类级别注解
Spring容器根据注解的过滤规则扫描读取注解Bean定义类,并将其注册到Spring IoC容器中
2.类内部注解
@Autowire、@Value、@Resource
都是在类内部的字段或者方法上的类内部注解
SpringIoC容器通过Bean后置注解处理器解析Bean内部的注解
1. 注解分析
基于java的接口进行实现,是一种特殊的接口类型,通常对于注解来说,三种情况
RetentionPolicy�
- SOURCE�
- 在编译前就会被丢弃
- CLASS�
- 编译后留在class中
- RUNTIME��
- 一直存在,运行的时候注解也会被保留
2. Autowired�
- 包名
package org.springframework.beans.factory.annotation;
- 定义
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
- �作用
@Autowired常用来作属性的注入,可以作用在构造方法、普通方法、字段、注解、参数上。
Spring中 AutowiredAnnotationBeanPostProcessor 处理器负责处理@Autowired注解相关注入。
- 使用
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
}
public class Student {
@MyAutowired
public Money money;
public void show(){
System.out.println(money.moneyCount+"Student say");
}
}
public class Money {
public int moneyCount = 300;
}
public class Application {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
SpringApplication.run(Application.class, args);
Student a = new Student();
Class<? extends Student> clazz = a.getClass();
Field[] fields = clazz.getFields();
for (Field field : fields) {
MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
if (myAutowired != null) {
Class fieldClass = field.getType(); // 在这里就是B.class
Money b = (Money) fieldClass.newInstance();
field.set(a, b);
}
}
a.show();
}
}
2. 自定义注解解析
- 拦截器解析
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
boolean required() default true;
}
@Component
public class MyTestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了拦截器……");
if (!(handler instanceof HandlerMethod)){
return true;
}
Method method = ((HandlerMethod) handler).getMethod();
MyTest annotation = method.getAnnotation(MyTest.class);
if (annotation != null){
boolean required = annotation.required();
if (required) {
//业务逻辑处理
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
@Configuration
public class ApiConfig extends WebMvcConfigurationSupport {
@Autowired
private MyTestInterceptor myTestInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.myTestInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
- AOP 解析
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
boolean required() default true;
}
@Component
@Aspect
public class MyTestAspect {
@Pointcut("@annotation(com.wyc.MyTest)")
private void pointCut(){ }
@Around("pointCut()")
public void advice(JoinPoint joinPoint){
System.out.println("执行了切面……");
}
// @Before("pointCut()")
// public void before(JoinPoint joinPoint){
// System.out.println("执行了切面……");
// //业务逻辑处理……
// }
}
3. @ApiVersion�
- 需求
对同一个API接口进行多版本的管理
- 方案
- 不对API进行版本管理
每次版本升级都强制用户更新升级
2. 不同版本用不同域名
针对域名转发到部署了不同版本应用的服务器,http://v1.com ,v2.com,http://v3.com 的域名分别转发到部署了对应版本的应用服务器
3. 维护多个版本的代码
在代码里面维护多个版本的API,保存多个版本的接口
- 思路
- 通过注解来标识不同接口的版本
- 通过URL和请求Header 里面的apiversion值来建立与Controller不同版本方法的关系
- 根据URL+apiversion 来执行对应版本的Controller方法
- 实现
- 定义注解
- 实现 RequestCondition
� 定义排序对象 - 重新定义Handler通过继承RequestMappingHandlerMapping,重写getCustomTypeCondition(Class<?> handlerType)和getCustomMethodCondition(Method method)方法
- 把自定义的RequestMappingHandlerMapping设置成默认的HandlerMapping交给spring管理,通过继承WebMvcConfigurationSupport 重写requestMappingHandlerMapping()方法
- 待完善
@RequestMapping("/wyc")
@RestController
//@ApiVersion("1")
public class TestAPIVersionController {
@GetMapping("/hello")
@ApiVersion(1)
public String hello1(){
return "version 1";
}
@GetMapping("/hello")
@ApiVersion(2)
public String hello2(){
return "version 2";
}
@RequestMapping("/hello")
@ApiVersion(3)
public String hello3(){
return "version 3";
}
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface ApiVersion {
int value();
}
public class ApiRequestCondition implements RequestCondition<ApiRequestCondition> {
private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile(".*v(\\d+).*");
private int apiVersion;
public ApiRequestCondition(int apiVersion){
this.apiVersion = apiVersion;
}
public int getApiVersion(){
return apiVersion;
}
@Override
public ApiRequestCondition combine(ApiRequestCondition other) {
return new ApiRequestCondition(other.getApiVersion());
}
@Override
public ApiRequestCondition getMatchingCondition(HttpServletRequest request) {
//默认版本号 请求错误时使用最新版本号
Integer version = 9999;
String murl = request.getRequestURI();
String apiversion = request.getHeader("apiversion");
System.out.println(murl);
if(!StringUtils.isEmpty(apiversion)){
Matcher m = Pattern.compile("v(\\d+)").matcher(apiversion);
Boolean status = m.find();
if (status == true){
version = Integer.valueOf(m.group(1));
}
}
System.out.println("version:"+version+",apiVersion:"+this.apiVersion);
//返回<=请求版本号的版本
if (version <= this.apiVersion){
// return this;
}
return null;
}
@Override
public int compareTo(ApiRequestCondition other, HttpServletRequest request) {
//对符合版本的版本号排序
String reqver = request.getHeader("apiversion");
System.out.println("compareTo-->other:"+other.getApiVersion()+",thisversion:"+this.apiVersion+",req-version:"+reqver);
return other.getApiVersion() - this.apiVersion;
}
}
public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private static final String VERSION_FLAG = "{version}";
private static RequestCondition<ApiRequestCondition> createCondition(ApiVersion apiVersion) {
// RequestMapping classRequestMapping = clazz.getAnnotation(RequestMapping.class);
// if (classRequestMapping == null) {
// return null;
// }
// StringBuilder mappingUrlBuilder = new StringBuilder();
// if (classRequestMapping.value().length > 0) {
// mappingUrlBuilder.append(classRequestMapping.value()[0]);
// }
// String mappingUrl = mappingUrlBuilder.toString();
// if (!mappingUrl.contains(VERSION_FLAG)) {
// return null;
// }
// ApiVersion apiVersion = AnnotationUtils.findAnnotation(clazz, ApiVersion.class);
// ApiVersion apiVersion = clazz.getAnnotation(ApiVersion.class);
if(apiVersion == null){
// return new ApiRequestCondition(1);
return null;
}
System.out.println(" create apiVersion:"+ apiVersion.value());
Integer currentval = apiVersion.value();
ApiRequestCondition apiRequestCondition = new ApiRequestCondition(apiVersion.value());
// ApiRequestCondition apiRequestCondition = apiVersion == null ? new ApiRequestCondition(1) : new ApiRequestCondition(apiVersion.value());
return apiRequestCondition;
}
@Override
protected RequestCondition<ApiRequestCondition> getCustomTypeCondition(Class<?> handlerType) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
// return createCondition(handlerType);
return createCondition(apiVersion);
// return super.getCustomTypeCondition(handlerType);
}
@Override
protected RequestCondition<ApiRequestCondition> getCustomMethodCondition(Method method) {
ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
// return createCondition(method.getClass());
return createCondition(apiVersion);
}
// private RequestCondition<ApiRequestCondition> createCondition(ApiVersion apiVersion) {
// return apiVersion == null ? null : new ApiRequestCondition(apiVersion.value());
// }
}
//@EnableSwagger2
@Configuration
@SuppressWarnings({"unused"})
class WebApiVesionConfig extends WebMvcConfigurationSupport {
@Autowired
private MyTestInterceptor myTestInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.myTestInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
@Autowired
public FormattingConversionService mvcConversionService;
@Autowired
public ResourceUrlProvider mvcResourceUrlProvider;
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new CustomRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors(mvcConversionService,mvcResourceUrlProvider));
return handlerMapping;
// return new CustomRequestMappingHandlerMapping();
}
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(ContentNegotiationManager contentNegotiationManager, FormattingConversionService conversionService, ResourceUrlProvider resourceUrlProvider) {
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, resourceUrlProvider);
}

浙公网安备 33010602011771号