经验整理-10-注解汇总-100-@-及常见问题-注解不生效问题

4 篇文章 0 订阅
1 篇文章 0 订阅

**java中常用的注解分三类:
1.JDK注解
2.Java第三方注解:spring、springmvc、springboot、dubbo
3.自定义注解**

-----------JDK注解-----

1、@Resource
详解
@Resource注解与@Autowired注解作用非常相似
@Resource的装配顺序:
(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错
@Autowired和@Resource两个注解的区别:
(1)、@Autowired默认按照byType方式进行bean匹配(多实例报错,巧记,@Autowired是spring推荐单例自动注入,按类型装配,适合单例,,@Resource是J2EE的annotation包下自带的,默认按照byName方式进行bean匹配(适合多实例按名称注入)
附:
@Reference是dubbo自带的注入注解
(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

1)、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

2)、不同点
(1)@Autowired
@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入

2、@PostConstruct

@PostConstruct注解好多人以为是Spring提供的。其实是Java自己的注解。
Java中该注解的说明:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。

通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:
Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

参考:https://blog.csdn.net/qq360694660/article/details/82877222

@PostConstruct与static的区别:构造方法的加载都在@PostConstruct注解的方法前,而static修饰的方法是在构造方法前的(当前类,所以static比@PostConstruct更优先加载)


-----------Java第三方注解-----


spring注解
1、工厂实例化注解,需加扫描包配置:<context:component-scan base-package="***"/>

@org.springframework.stereotype.Service   标注一个业务逻辑组件类。 
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进- 行标注。
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Bean,就会作为这个Spring容器中的Bean。
@Configuration
从Spring3.0,
@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器
2、注入bean注解
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
3、其他注解
@Lazy(true) 表示延迟初始化
@org.springframework.stereotype.Service用于标注业务层组件、
@Scope 用于指定scope作用域的(用在类上)
@javax.annotation.PostConstruct 修饰init方法,那么spring就会在该bean的依赖关系注入完成之后回调该方法。
@PreDestroy destroy方法之后,实例
@Async异步方法调用

springMVC注解

参考:https://www.cnblogs.com/airen123/p/9001454.html

1、@Controller
在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
  (1)在SpringMVC 的配置文件中定义MyController 的bean 对象。 
  (2)在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。
<!--方式一-->
<bean class="com.host.app.web.controller.MyController"/>
<!--方式二-->
< context:component-scan base-package = "com.host.app.web" />//路径写到controller的上一层(扫描包详解见下面浅析)
 
2、@RequestMapping 
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。 
RequestMapping注解有六个属性,下面我们把她分成三类进行说明(下面有相应示例)。
1、 value, method; 
value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明); 
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
2、consumes,produces 
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html; 
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
3、params,headers 
params: 指定request中必须包含某些参数值是,才让该方法处理。 
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
3、@Resource和@Autowired 
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
4、@ModelAttribute和 @SessionAttributes 
代表的是:该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。
@SessionAttributes即将值放到session作用域中,写在class上面。
具体示例参见下面:使用 @ModelAttribute 和 @SessionAttributes 传递和保存数据
5、@PathVariable 
用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。
6、@requestParam 
@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter(“name”),它有三个常用参数:defaultValue = “0”, required = false, value = “isApp”;defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
7、@ResponseBody 
作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
8、@Component 
相当于通用的注解,当不知道一些类归到哪个层时使用,但是不建议。
9、@Repository 
用于注解dao层,在daoImpl类上面注解。

注: 
1、使用 @RequestMapping 来映射 Request 请求与处理器 
方式一、通过常见的类路径和方法路径结合访问controller方法 
方式二、使用uri模板


springboot注解

@SpringBootApplication:包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文。
@Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全。
@EnableAutoConfiguration 自动配置。
@ComponentScan 组件扫描,可自动发现和装配一些Bean。
@Component可配合CommandLineRunner使用,在程序启动后执行一些基础任务。
@RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。
@Autowired自动导入。
@PathVariable获取参数。
@JsonBackReference解决嵌套外链问题。
@RepositoryRestResourcepublic配合spring-boot-starter-data-rest使用。
@ResponseBody:表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用。
@RestController:用于标注控制层组件(如struts中的action),@ResponseBody和@Controller的合集。
@ComponentScan:表示将该类自动发现扫描组件。
@Import:用来导入其他配置类。
@ImportResource:用来加载xml配置文件。
@Autowired:自动导入依赖的bean
@Value:注入Spring boot application.properties配置的属性的值。

hibernate注解

@Entity:将pojo类标记成实体,可以指定一个name属性,指定实体类的名称
@Table:注释改持久化类所映射的表
@UniqueConstraints:用于数据表的唯一约束 columnNames属性
@Index用于数据库建立索引
@DynamicInsert:指定用于插入记录的insert语句是否在运行时动态生成。并且只插入那些非空字段。默认值时false
@DynamicUpdate:指定用于更新巨鹿的update语句是否在运行是时动态生成,并且只更新那些修改过的字段,默认值是否false
@SelectBeforeUpdate:制动Hbiernate在更新某个持久化对象之前是否进行一次select(建议false)
@NotBlank只能作用在String上,不能为null,而且调用trim()后,长度必须大于0

#swagger2注解

@Api()用于类; 表示标识这个类是swagger的资源
@ApiOperation()用于方法; 表示一个http请求的操作
@ApiParam()用于方法,参数,字段说明;表示对参数的添加元数据(说明或是否必填等)
@ApiModel()用于类 表示对类进行说明,用于参数用实体类接收
@ApiModelProperty()用于方法,字段;表示对model属性的说明或者数据操作更改
@ApiIgnore()用于类,方法,方法参数 ;表示这个方法或者类被忽略
@ApiImplicitParam() 用于方法 ;表示单独的请求参数
@ApiImplicitParams() 用于方法,包含多个 @ApiImplicitParam
Mybaits注解
@Select 简单查询
@Insert 简单插入
@Update 简单更新
@Delete 简单删除
@Param : 入参
@Results : 结果集合
@Result : 结果

lombok整理

@Data 注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
@Setter :注解在属性上;为属性提供 setting 方法
@Setter :注解在属性上;为属性提供 getting 方法
@Log4j :注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
@NoArgsConstructor :注解在类上;为类提供一个无参的构造方法
@AllArgsConstructor :注解在类上;为类提供一个全参的构造方法
@Cleanup : 可以关闭流
@Builder : 被注解的类加个构造者模式
@Synchronized : 加个同步锁
@SneakyThrows : 等同于try/catch 捕获异常
@NonNull : 如果给参数加个这个注解 参数为null会抛出空指针异常
@Value : 注解和@Data类似,区别在于它会把所有成员变量默认定义为private final修饰,并且不会生成set方法
@ToString:无需启动调试器即可查看您的字段,注解会自动重写对应的toStirng方法


dubbo整理

@org.apache.dubbo.config.annotation.Service   //PS:若使用的是dubbo的Service注解时,在controller注入的时候,要选择@Reference注解来进行注入。
@org.apache.dubbo.config.annotation.Reference

附:Reference的一些核心属性
timeout:服务超时时间,单位:毫秒(这个设置是由优先级的,详情见dubbo配置优先级)
version:服务版本,与服务提供者保持一致,如果有多个版本的服务提供者可以动态选择
group:服务分组,当一个接口有多个实现的,可以使用分组进行区分,必须和服务提供方保持一致
retires:重试次数,默认为0
loadbalance:负载均衡策略,参数值为:random(随机), roundrobin(轮询), leastactive(最少活跃调用)
url:点对点直连服务提供者的地址,可以绕过注册中心。因为在dubbo启动之后,注册中心宕掉也可以通过本地缓存选择服务提供者进行调用,所以绕过注册中心,直连服务提供者也是可以的。
registry:指定注册中心注册获取服务列表,多个注册中心的话使用逗号隔开。
actives:每个服务消费者每个服务方法最大并发调用数。
protocol:只调用指定协议的服务提供方

 

-----------自定义便捷注解-----

万能性方法环绕注解示例:
 

参考:字段注解 https://blog.csdn.net/junmoxi/article/details/77744656?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158468996119724845047705%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158468996119724845047705&biz_id=0&utm_source=distribute.pc_search_result.none-task

一、定义可用的注解接口(理解为对往暴露的一个可用的注解壳子,没有实现复杂的逻辑)

先认识四种元注解,专门注解其他的注解:
巧记:文档周期继承目标
   @Documented –注解是否将包含在JavaDoc中
   @Retention –什么时候使用该注解
   @Target –注解用于什么地方
   @Inherited – 是否允许子类继承该注解

@Target(ElementType.FIELD)//注解的作用范围,就是注解是用在什么地方的
@Retention(RetentionPolicy.RUNTIME)//注解的级别,就是注解能留存到什么时候
@Documented
@Inherited
public @interface MyAnnotation {
    public String value();//注解可以接收的参数
}

二、注解处理器(自定义注解的业务实现逻辑入口在这)

参考:https://blog.csdn.net/u010590685/article/details/47066865?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158469116919725211922876%2522%252C%2522scm%2522%253A%252220140713.130056874..%2522%257D&request_id=158469116919725211922876&biz_id=0&utm_source=distribute.pc_search_result.none-task

 

public class Inject {
    public static void injectfeild(Object o){
         Class<?> clazz = o.getClass();  //获得传进来的类
         Field[] fields = clazz.getDeclaredFields();//通过反射获取类的域(全局变量)
         for (Field field : fields) { 
            // 查看这个字段是否有我们自定义的注解类标志的  
             if (field.isAnnotationPresent(MyAnnotation.class)) {  
                 MyAnnotation inject = field.getAnnotation(MyAnnotation.class);  //获取到我们的注解
                 String value=inject.value();//获取注解的参数
                 field.setAccessible(true);
                 try {
                  //处理注解想要实现的业务逻辑
                } catch (IllegalArgumentException | IllegalAccessException e) {

                    e.printStackTrace();
                }
             }
         }
    }
}

三、获取获取指定注解字段的值

  /**
     * @Author: Jiangxiaopeng
     * @Description:获取指定注解字段的值
     * @Date: 2020/6/3
     * Object object2 已知对象
     * String reNameValue 注解字段指定重命名的名称
     **/
    public static String getFeiledValueByObject(Object object2 , String reNameValue) throws IllegalAccessException {
        Field[] fields = object2.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ReNameAnnotation.class)) {
                ReNameAnnotation reNameAnnotation = (ReNameAnnotation) field.getAnnotation(ReNameAnnotation.class);
                String reName= reNameAnnotation.reName();
                if(reNameValue.equals(reName)){
                    field.setAccessible(true);
                    Object o=field.get(object2);
                    String a1 =o.toString();
                    return a1;
                }
            }
        }
        return null;
    }

    /**
     * @Author: Jiangxiaopeng
     * @Description:获取指定注解字段的值
     * @Date: 2020/6/3
     * ProceedingJoinPoint point 通过他拿到方法入参所有对象,然后遍历
     * String reNameValue 注解字段指定重命名的名称
     **/
    public static String getFeiledValueByPoint(ProceedingJoinPoint point,String reNameValue) throws IllegalAccessException {
//        Field[] fields = clazz.getDeclaredFields();
        Object[] args = point.getArgs();
        for (Object object : args) {
            Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ReNameAnnotation.class)) {
                ReNameAnnotation reNameAnnotation = (ReNameAnnotation) field.getAnnotation(ReNameAnnotation.class);
               String reName= reNameAnnotation.reName();
               if(reNameValue.equals(reName)){
                   field.setAccessible(true);
                   Object o=field.get(object);
                   String a1 =o.toString();
                   return a1;
               }
            }
        }
        }
        return null;
    }


--------------------常见问题--------------------
--------------------解决问题----------------

 

问题1:注解内想获取业务目标上的入参的私有变量怎么获取?

(报错----Java反射操作私有成员变量 Class can not access a member with modifiers "private")

解决:https://blog.csdn.net/hanchao5272/article/details/79435358
通过反射操作类的私有(private)成员变量时,需要通过field.setAccessible(true)将字段设置为可以访问的。

 

问题1:注解内有一些情况是获取不到的,注解不生效,怎么解决?

1) 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。不然将被忽略,也不会抛出任何异常。

解决:

2)同一个service实现类中某个方法1调用了本类中的另一个方法2.
方法2上的注解是不走aop代理类对象的,走的自身当前对象,所以不会生效。

参考:https://blog.csdn.net/weixin_34116110/article/details/88850520?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_para

为什么能够切入目标对象,原理就是创建了代理类,在代理类中调用目标方法前后进行切入;假如代理对象是$proxy0,对于B方法$proxy0.B(),执行流程就是先记录日志再调用目标对象s的B方法,所以可以切入;但是A方法$proxy0.A(),只能对A方法增强,A里面调B的时候使用的是s目标对象s.B(),而不是$proxy0.B(),所以对B的切入无效,因为压根就没用代理对象去调用;

解决:

解决内部调用没有生效的几种方法:
2.1)bean自引用调用;

2.2)获取当前代理对象;


2.3)拆成独立的实现类,再来调用;

 

3)另外提一下事物注解,默认是只处理运行时异常的。

解决:在catch中 throw new RunTimeException 或者setrollbackonly()或者在

@Transactional(rollbackFor=Exception)直接指定所有异常

 

 

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java_爱吃肉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值