spring预热(1)——注解

注解的作用,可以编写文档,可以进行代码分析,可以进行编译检查等等,后面慢慢说,下面先描述一下注解。


java自带的注解之一 —— 标准注解

  • @Override,表示当前方法将要覆盖父类的方法。使用这个注解,然后如果没有覆盖成功,编译器会出错。

    如果不用这个注解,编译器大部分时候会认为你在子类写了个新方法,这就与我们的想法不同了。

  • @Deprecated,如果你给一个元素加上了这个注解,然后又使用了这个元素,那么会出现一个警告信息。

  • @SuppressWarnings,关闭(不当的)编译器警告。如果你在一处警告加上了这个注解,那么这个警告就消失了(表面上)。


java自带的注解之二 —— 元注解,以及自定义注解

元注解专门负责注解其他的注解。

日常使用的大部分注解都是自己定义的。这个时候就会用到元注解。下面通过一个栗子来说明

首先我们来自定义一个注解:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Test {}   
  • 这里,我们自定义了一个注解@Test,定义的时候很像接口,不过用的是@interface,多了个“@”。

    和其他任何java接口一样,注解也将会编译成class文件。

  • 定义注解,这里用到了两个元注解:@TargetRetention。前一个定义新写的注解可以用在什么地方,后一个来定义该注解可以在哪里使用(源代码、类文件或者运行时)。可以看到使用这两个元注解的时候,往里面分别传了值。

    所有的元注解以及可以取的值以及具体的含义如下:

    1. @Target:表示该注解可以用于什么地方。可能的ElementType参数如下

      ElementType说明
      CONSTRUCTOR构造器的声明
      FIELD域声明(包括enum实例)
      LOCAL_VARIABLE局部变量声明
      METHOD方法声明
      PACKAGE包声明
      PARAMETER参数声明
      TYPE类、接口(包括注解类型)或enum声明
    2. @Retention:表示需要在什么级别保存该注解信息。可选的RententionPolicy参数包括:

      RententionPolicy说明
      SOURCE注解将被编译器丢弃
      CLASS注解在class文件中可用,但会被虚拟机(VM)丢弃
      RUNTIMEVM将在运行期也被保留,因此可以通过反射机制读取注解信息
    3. @Documented:将此注解包含在Javadoc中。

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

    大多数情况下,程序员一般自己定义注解。(不过Override算是用的最多的)

  • 在注解中,你可以包含一些元素来表示一些值。在这里,你可以为这些被包含的元素指定默认值。下面针对这一点再来举个栗子:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Test2 {
        public int id();
        public String name() default "yiran";
    }

    在这里,注解Test2定义了两个元素:idname(注意这里要在元素名后面加())。然后给元素name设定了一个默认值,通过default。如果使用该注解的时候,没有给出name元素的值,那么将使用默认值。下面来举个栗子:

        @Test2(id = 3, name = "zhangsan")
        public void testMethod3() {}
    
        @Test2(id = 4)
        public void testMethod4() {}

上面这个栗子中,第一个注解对两个元素都进行了赋值,而第二个注解只对id进行了赋值,那么此时name的值为“yiran”(默认值)。

以上就是自定义一个注解,下面来说明如何通过注解处理器来处理注解


注解处理器

通过反射来处理注解。当一个注解被定义为“运行时可见”,那就可以使用反射。

Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素。这个接口的实现类包括Class、Constructor、Field、Method、Package。

只要获取了某个程序元素的class,就可以获取这个元素里面的所有子元素(比如类里面的方法等等),就可以获取每一个元素子元素的注解。在AnnotatedElement 里面定义了四个方法:

1. getAnnotation:
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
这个方法返回了该元素指定类型的注解,显然是 某个元素. 来调用。
参数 对应注解的class对象。
返回 是对应注解的对象或者`null`。

2. getAnnotations:
Annotation[] getAnnotations()

3. getDeclaredAnnotations:
Annotation[] getDeclaredAnnotations()
这个方法返回此元素上面所有的注解,以数组的形式返回。与上面那个不同,这个方法只返回直接存在于该元素上的注解,继承来的注解不管。

4.isAnnotationPresent:
boolean isAnnotationPresent
(Class<? extends Annotation> annotationClass)
如果此元素上有指定的注解,返回true;否则返回false。

这里再来说一下反射,这里通过反射可以获得一个类中所有的东西,包括但不限于方法、变量等等,然后再通过上面的四种方法,可以获得每个“东西”(即“元素”)上的注解。

元素包括:
  Class:类定义
  Constructor:构造器定义
  Field:累的成员变量定义
  Method:类的方法定义
  Package:类的包定义

例如:Class既是类定义,又是元素

总之,只要能通过反射获得元素,就可以获得一切。


乱七八糟

  1. 标签中可用的元素(和上面刚说过的不太一样。。又感觉差不多)种类包括:

    • 所有基本类型(不允许使用包装类型)
    • String
    • Class
    • enum
    • Annotation
    • 以上类型的数组

    从上面看,注解可嵌套

  2. 关于注解中的元素(好不容易和上面那个元素分开了)
    元素不能有不确定的值,即要么使用注解时设定值,要么使用默认值。

    但是,对于非基本类型的元素,不能设为null,无论是默认值还是使用时设定

  3. 注解不支持继承,即不能写一个新注解,然后extend一个老注解。


目前就先写这么多。目前看来,注解使用的场合越来越多,比如Spring中十分推荐使用注解配置bean。以上仅仅为注解的入门,注解尤其是注解处理器还能玩出非常大的花样。不过接下去应该还是会写一写关于Spring中用到的其他东西,不然乍一学蒙圈好久。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP是Spring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值