Spring--注解

一、简介

Spring注解是一种元数据形式的代码,用于提供配置信息,从而减少XML配置文件的使用。Spring框架提供了一系列的注解,用于简化Spring应用程序的开发。通过使用这些注解,开发者可以在不编写大量XML配置的情况下,实现对Spring容器中bean的声明和管理、自动装配依赖、声明事务管理等功能。

二、常用注解

  1. @Component:表示一个类是Spring容器管理的组件,可以被自动扫描并注册到Spring应用上下文中。
  2. @Controller:是@Component的特化,用于标注控制层的组件,处理用户请求和返回响应。
  3. @RestController:是@Controller和@ResponseBody的组合,简化了RESTful Web服务的编写。
  4. @Service:是@Component的特化,用于标注服务层的组件。
  5. @Repository:是@Component的特化,用于标注数据访问层的组件,通常与数据库交互。
  6. @Configuration:表示一个类是配置类,可以包含一个或多个@Bean注解的方法。
  7. @Bean:表示一个方法产生一个bean,该方法的返回值将被注册到Spring应用上下文中。
  8. @Autowired:用于自动注入依赖关系,它可以应用于字段、构造函数、setter方法等。
  9. @Qualifier:与@Autowired结合使用,指定要注入的确切的bean实例。
  10. @RequestMapping:用于映射Web请求到控制器的处理方法,可以指定URL模式、HTTP方法等。
  11. @PathVariable:用于从URL的一部分中提取变量值,并将其作为方法参数。
  12. @ResponseBody:指示方法的返回值应该直接写入HTTP响应体中,通常与@RequestMapping一起使用。
  13. @Transactional:用于声明事务的边界,确保事务的一致性和原子性。
  14. @EnableTransactionManagement:启用声明式事务管理。

三、元注解

Spring框架中的元注解是指那些用于注解其他注解的注解。它们提供了一种机制来定义新的注解,并指定这些新注解的行为和作用范围。Spring提供了几个核心的元注解,这些元注解可以用来创建自定义注解,以下是一些常用的Spring元注解:

  1. @Target:指定自定义注解可以应用于哪些Java元素,如类、方法、构造函数、字段或注解等。它接受ElementType枚举的一个或多个值作为参数,常用的枚举值有:
    • ElementType.TYPE:说明该注解只能被声明在一个类前;
    • ElementType.FIELD:说明该注解只能被声明在一个类的字段前;
    • ElementType.METHOD:说明该注解只能被声明在一个类的方法前;
    • ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前;
    • ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前;
    • ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前;
    • ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前;
    • ElementType.PACKAGE:说明该注解只能声明在一个包名前。
  2. @Retention:确定自定义注解在何种生命周期内有效。它有三个可能的值:
    • RUNTIME:表示注解在运行时依然存在;
    • CLASS:表示注解仅在编译后的.class文件中保留;
    • SOURCE:表示注解仅在源代码中有效,编译时会被丢弃。
  3. @Documented:指示Javadoc工具应该记录自定义注解。当你希望在生成的API文档中包含自定义注解时,应该使用这个元注解。
  4. @Inherited:表示自定义注解可以被子类继承。如果一个注解被标注为@Inherited,那么其父类上的该注解也会出现在子类上。

四、注解的原理

Spring框架中的注解原理基于Java的反射API和代理技术,主要涉及以下几个方面:

  1. 注解扫描:

    • Spring容器启动时,会根据@ComponentScan注解指定的基础包路径,扫描类路径下所有带有特定注解(如@Component、@Service、@Repository、@Controller等)的类。
    • 这些注解通常会通过@Component或其特化注解来标记Spring容器应该管理的组件。
  2. Bean的实例化和注册:

    • 被扫描到的带有Spring管理注解的类将被实例化。如果该类有无参构造函数,Spring会使用默认无参构造函数创建实例;如果没有无参构造函数,可能会使用CGLIB等字节码操作库进行实例化。
    • 创建的实例会被注册到Spring容器中,以便之后进行依赖注入。
  3. 依赖注入:

    • Spring容器会根据注解如@Autowired、@Inject、@Resource等来确定依赖关系,并通过反射机制将依赖注入到目标Bean中。
    • 如果依赖是由方法参数或者构造函数指定的,Spring会尝试匹配相应类型的Bean进行注入。
    • 如果依赖是字段,Spring会直接设置字段的值。
  4. 代理创建:

    • 对于需要AOP(面向切面编程)功能的Bean,Spring会创建一个代理对象。这个代理对象会拦截对目标Bean的调用,并在适当的时机执行通知逻辑。
    • 代理可以是JDK动态代理(仅适用于实现了接口的类)或者基于CGLIB的代理(适用于所有类,包括抽象类和没有实现接口的类)。
  5. Bean的生命周期管理:

    • Spring容器负责管理Bean的整个生命周期。在Bean初始化时,会调用初始化方法(如@PostConstruct注解的方法)。
    • 在Bean销毁时,会调用清理方法(如@PreDestroy注解的方法)。
  6. 事件发布和监听器机制:

    • Spring容器在Bean的生命周期事件发生时,会发布相应的事件,比如ContextRefreshedEvent、ContextClosedEvent等。
    • 可以注册监听器(Listener)来响应这些事件,从而实现一些自定义的逻辑。

五、自定义注解

自定义注解是通过使用@interface关键字来创建的。自定义注解可以用来为类、方法、变量等添加元数据信息。自定义注解本身也可以被其他注解修饰。以下是创建和使用自定义注解的基本步骤:

  1. 定义注解:使用@interface关键字来定义一个注解类型。可以指定注解的保留策略(@Retention)、允许的目标(@Target)等。
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)  // 注解在运行时依然存在
@Target(ElementType.FIELD) // 注解作用于字段上
@Documented  // 注解将包含在JavaDoc中
@Inherited   // 注解来允许注解被继承
public @interface CustomAnnotation {
    String value();
    String name() default "defaultName";  // 为注解的元素提供默认值
}
  1. 使用注解:在类、方法、变量等元素上使用定义好的注解。
public class ExampleClass {
    @CustomAnnotation("exampleValue")
    private String exampleField;
}
  1. 处理注解:在程序运行时,可以使用反射API来检测注解,并根据注解的信息执行相应的逻辑。
import java.lang.reflect.Field;

public class AnnotationProcessor {
    public static void processAnnotations(Object object) throws IllegalAccessException {
        Class<?> clazz = object.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(CustomAnnotation.class)) {
                CustomAnnotation annotation = field.getAnnotation(CustomAnnotation.class);
                String value = annotation.value();
                System.out.println("Found annotation with value: " + value);
            }
        }
    }
}

六、自定义注解与AOP整合

在Spring框架中,通过将自定义注解和AOP结合使用,可以对业务逻辑进行非侵入式的增强。下面是如何创建自定义注解并将其应用于切面的详细步骤:

  1. 定义自定义注解:首先,需要定义一个自定义注解,该注解可以包含一些元数据,如目标方法的名称、执行顺序等。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
    // 可以定义更多的属性,例如优先级等
}
  1. 创建切面类:接着,创建一个切面类,并定义通知(Advice),通知是指在切点匹配的方法执行前后或抛出异常时执行的代码块。
@Aspect
public class LoggingAspect {

    // 定义切点表达式,匹配带有LogExecutionTime注解的方法
    @Pointcut("@annotation(com.example.annotation.LogExecutionTime)")
    public void methodsAnnotatedWithLogExecutionTime() {}

    // 在目标方法前执行的通知
    @Before("methodsAnnotatedWithLogExecutionTime()")
    public void logBefore(JoinPoint joinPoint) {
        long start = System.currentTimeMillis();
        System.out.println("Starting method: " + joinPoint.getSignature().getName());
    }

    // 在目标方法后执行的通知
    @After("methodsAnnotatedWithLogExecutionTime()")
    public void logAfter(JoinPoint joinPoint) {
        long end = System.currentTimeMillis();
        System.out.println("Ending method: " + joinPoint.getSignature().getName() + " in " + (end - start) + "ms");
    }
}
  1. 启用AOP支持:在Spring配置文件中,或者使用Java配置来启用AOP支持。
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // 其他配置...
}
  1. 使用自定义注解:最后,将自定义注解应用于需要被切面处理的方法上。
@Service
public class SomeService {

    @LogExecutionTime
    public void someBusinessMethod() {
        // 业务逻辑
    }
}

在上述示例中,LogExecutionTime注解被定义并用于标记特定的方法。LoggingAspect切面类定义了两个通知方法:logBefore和logAfter,它们分别在带有LogExecutionTime注解的方法执行前后执行。通过@EnableAspectJAutoProxy注解,Spring容器会自动为切面生成代理对象,从而使得通知能够在目标方法执行时被触发。通过这种方式,可以非常灵活地为不同的业务逻辑添加额外的行为,而无需修改原有代码,这正是AOP的强大之处。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值