java自定义注解的作用和案例

目录

一,Java注解

二,元注解

1,@Target

2,@Retention

2.1 RUNTIME =>  @Service 

2.2 CLASS    => 

2.3   SOURCE   =>  @Override

2.4  那怎么来选择合适的注解生命周期呢?

3, @Documented

4, @Inherited

5, @Repeatable

三,作用和案例

1,路由需求

1.1,自定义注解

1.2,自定义注解逻辑实现

1.3,自定义注解调用


一,Java注解

Java注解是一种元数据形式,可以被添加到Java代码中的各种元素(类、方法、字段等)上,以提供关于这些元素的额外信息。注解是在Java 5中引入的一项特性,它们不直接影响代码的执行,而是提供了一种机制来对代码进行标记和解释。

注解通常以@符号开头,放置在注解目标前面。Java提供了一些内置的注解(如@Override和@Service等),同时也可以自定义注解。

二,元注解

提起自定义注解 就绕不开元注解,就像饭菜离不开食材。

那什么是元注解,可以理解为其他普通注解进行解释说明,下面是5种元注解的简单总结:



1,@Target

该注解的使用范围,限定应用场景。枚举类 ElemenetType 中

 TYPE:类,接口
 FIELD:字段,枚举的常量
 METHOD:函数(方法)
 PARAMETER:参数
 CONSTRUCTOR:构造函数
 ANNOTATION_TYPE:注解类型
 LOCAL_VARIABLE:局部变量
 PACKAGE:包

2,@Retention


该注解的生存周期,相当于时间戳。
注解生命周期的三个阶段:java源文件是一个阶段;class文件是一个阶段;内存中的字节码是一个阶段。
javac把java源文件编译成.class文件时,去掉里面的RUNTIME注解
类加载器把.class文件加载到内存时,去掉里面的CLASS注解
最后剩下的就是SOURCE注解

枚举类型 RetentionPolicy 中

 SOURCE:在源文件中有效,编译后会被丢弃(如@Override,@Deprecated)
 CLASS:在class文件中有效,在jvm丢弃
 RUNTIME:在运行时有效,class文件保留,jvm运行时保留(很多框架运用反射调用)


2.1 RUNTIME =>  @Service 

2.2 CLASS    => 

暂时没遇上,后续遇上会补上

2.3   SOURCE   =>  @Override

@Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处: 

1>可以当注释用,方便阅读 

2>编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错 
​​​​​​​

2.4  那怎么来选择合适的注解生命周期呢?

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;
如果要 在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife) ,就用 CLASS注解;
如果 只是做一些检查性的操作,比如 @Override 则 可选用 SOURCE 注解。

 

 

3, @Documented


javadoc文档生成工具的使用

4, @Inherited


允许子类继承父类中的注解。

常见的是@SpringBootApplication和@Service对比:



5, @Repeatable


​​​​同一种注解可多次使用

三,作用和案例

注解为代码元素提供了额外的元数据信息。这些信息可以用于在编译时或运行时进行处理,以实现各种功能。
例如:

@Override注解用于标记方法覆盖父类的行为,这在编译时会进行检查。

@Service注解用于类上,标记当前类是一个service类,加上该注解会将当前类自动注入到spring容器中,不需要再在applicationContext.xml文件定义bean了。

个人现阶段任务自定义注解的作用是标定,用于标定某些具有共性的类,然后使用反射统一处理这些具有共性的类,下面例子就围绕这个进行:

1,路由需求

目前有多个不同的实例报文,需要进行处理,从控制器路由分发到具体的逻辑处理实现中是这样写的,要求是对此做出简化。

D001001ServiceImpl d001001Service = ServiceFactory.getServiceFactory().getApplicationContext().getBean(D001001ServiceImpl.class);
d001001Service.dowork(requestParam);

1.1,自定义注解

首先是写一个服务路由的注解:@ServiceRoute  

其中@Service的添加是由于使用的service类都需要@Service,为了精简代码。

package com.example.core.comm;

import org.springframework.stereotype.Service;
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
public @interface ServiceRoute {
    String routeKey();
}

1.2,自定义注解逻辑实现

使用注解处理器可以在编译时或运行时处理注解信息。注解处理器可以通过反射机制获取注解信息,并根据需要执行相应的操作。

实现一个工厂类ServiceFactory用于实现对应的路由逻辑:

逻辑就是获取spring容器中的bean,根据map特性使用注解中的标记属性找到对应的处理方法。

package com.example.core.comm;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ServiceFactory implements ApplicationContextAware {

    private  ApplicationContext applicationContext;
    private static  ServiceFactory serviceFactory = new ServiceFactory();
    private static Map<String,Object> sourceMap = new ConcurrentHashMap<>();

    public static ServiceFactory getServiceFactory() {
        return serviceFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     *     @PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
     *     通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:
     *     Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
     */
    @PostConstruct
    public  void getSourceMap(){
        //获取到所有拥有特定注解的Beans集合,然后遍历所有bean实现业务场景。
        Map<String,Object>  map  = this.applicationContext.getBeansWithAnnotation(ServiceRoute.class);

        for (String key:map.keySet()){
            Object obj = map.get(key);
            //根据bean,getAnnotation方法来获取指定注释类型的注释
            ServiceRoute sf = obj.getClass().getAnnotation(ServiceRoute.class);
            sourceMap.put(sf.routeKey(),obj);
        }
    }

   /**
   *获取指定注解的服务
   */
    public  Object getService(String routeKey){
        for (String  key:sourceMap.keySet()) {
            if (key.contains(routeKey)){
                return  sourceMap.get(key);
            }
        }
        return null;
    }

}

1.3,自定义注解调用


控制器Controller中的调用改为以下方式:

根据标识获取指定逻辑实现类

IBaseService iBaseService = (IBaseService) ServiceFactory.getServiceFactory().getService("D001.001.001");
  if (iBaseService != null){
     return   iBaseService.dowork(requestParam);
  }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值