0301声明Bean注解- IOC注解-spring

1 注解简单回顾

1.1 元注解

元注解(Meta-Annotation)是指注解上的注解,它是一种特殊的注解,用于标注其他注解的属性。元注解可以用来自定义注解的行为,包括定义注解的作用范围、生命周期、使用方式等信息。

在Java中,有四种元注解,分别是:

  1. @Target:用于指定注解的作用范围。它包括如下取值:
  • ElementType.TYPE:适用于类、接口、枚举等类型;
  • ElementType.FIELD:适用于字段、枚举常量等;
  • ElementType.METHOD:适用于方法;
  • ElementType.PARAMETER:适用于方法参数;
  • ElementType.CONSTRUCTOR:适用于构造方法;
  • ElementType.LOCAL_VARIABLE:适用于局部变量;
  • ElementType.ANNOTATION_TYPE:适用于注解;
  • ElementType.PACKAGE:适用于包。
  1. @Retention:用于指定注解的生命周期。它包括如下取值:
  • RetentionPolicy.SOURCE:表示注解只在源代码中保留,在编译后就被丢弃;
  • RetentionPolicy.CLASS:表示注解在编译时被保留在.class文件中,但在运行时不可见;
  • RetentionPolicy.RUNTIME:表示注解在运行时可见,并且可以通过反射机制获取,存在与编译后的.class文件和JVM虚拟机中。
  1. @Documented:用于指定注解是否应该包含在JavaDoc文档中。如果一个注解使用了@Documented元注解,它将被包含在JavaDoc文档中,否则不会被包含。
  2. @Inherited:用于指定注解是否可以被继承。如果一个注解使用了@Inherited元注解,它将会被其子类继承,否则不会被继承。

通过使用元注解,我们可以自定义注解的作用范围、生命周期、可见性等信息,从而更加灵活地定义和使用注解。在使用自定义注解时,通常需要根据实际情况选择合适的元注解来对其进行修饰。

1.2 别名

@AliasFor是Spring Framework中的一个元注解,用于定义注解属性的别名,也可以用于指定注解的派生关系。

  • 注解属性别名

它可以用来表示两个属性名称是互相等价的,如果使用了其中一个属性,另一个属性的值也会被自动赋值。

例如,假设我们有一个自定义的注解@MyAnnotation,它有两个属性name和value:

lessCopy code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String name() default "";
    String value() default "";
}

现在我们想要定义别名,使得name属性可以通过value属性来赋值,反之亦然。这时就可以使用@AliasFor元注解:

lessCopy code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    @AliasFor("value")
    String name() default "";
    @AliasFor("name")
    String value() default "";
}

在上面的代码中,我们通过@AliasFor(“value”)和@AliasFor(“name”)分别定义了name和value属性之间的互相别名关系。这样,在使用@MyAnnotation注解时,如果设置了name属性,value属性也会被自动赋值,反之亦然。

  • 指定注解的派生关系

@AliasFor元注解也可以用于指定注解的派生关系,使得派生注解中的某些属性可以与父注解中的属性互相别名。在这种情况下,使用@AliasFor元注解的属性必须要与父注解中的属性名称相同。

例如,假设我们有一个自定义的注解@ParentAnnotation,它有两个属性name和value:

lessCopy code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParentAnnotation {
    String name() default "";
    String value() default "";
}

现在我们想要定义一个子注解@ChildAnnotation,它派生自@ParentAnnotation,并且将name属性与父注解中的value属性互相别名。这时可以使用@AliasFor元注解:

lessCopy code
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ParentAnnotation
public @interface ChildAnnotation {
    @AliasFor(annotation = ParentAnnotation.class, attribute = "value")
    String name() default "";
}

在上面的代码中,我们通过@ParentAnnotation标注了@ChildAnnotation,表示它派生自@ParentAnnotation。同时,使用@AliasFor指定了name属性与父注解中的value属性互相别名。这样,在使用@ChildAnnotation注解时,如果设置了name属性,value属性也会被自动赋值为相同的值。

  • 注意事项

使用@AliasFor元注解可以使自定义注解更加灵活和易用,尤其是在定义注解的派生关系时。但需要注意的是,@AliasFor元注解的使用需要谨慎,必须保证别名属性的类型和默认值与目标属性相同,否则可能会导致意想不到的问题。

2 常用声明Bean注解

这些注解可以用来声明不同类型的Bean,并且可以指定Bean的属性、作用域、初始化方式等。在实际使用中,根据具体的场景和需求选择合适的注解来声明Bean,可以更加方便地管理和组织Spring应用中的各个组件。

这里我们只讲解下常用的声明Bean的注解,其他注解自行查阅相关文档。

2.1 普通组件类

常用声明一个普通组件类的注解有以下4种:

  • @Component
  • @Controller
  • @Service
  • @Repository

源码如下2.1-1所示:

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 组件类声明
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

   /**
    * 组件名
    */
   String value() default "";

}

/**
 * 声明控制器
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

	/**
	 * 组件名
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}

// 省略 @Service和@Repository,除了注解名不同,其他同Controller一样

在Spring框架中,@Controller、@Service和@Repository都是@Component注解的派生注解,即它们都包含了@Component注解的所有功能,同时还添加了一些特定功能。将它们定义为@Component注解的别名,主要是为了让开发者在不同的场景下使用更加方便。

具体来说,@Controller注解用于标识控制器类,表示这个类是一个处理HTTP请求的控制器;@Service注解用于标识服务层组件类,表示这个类是一个服务层组件;@Repository注解用于标识数据访问对象(DAO)类,表示这个类是一个数据访问对象。这些注解都是为了将不同类型的组件类在Spring应用中进行区分和管理。

使用@Component注解标记一个组件类时,需要为这个类指定一个具体的角色,如DAO、Service、Controller等。而通过将@Controller、@Service和@Repository注解定义为@Component注解的别名,就可以直接使用这些注解来标记组件类,而无需再指定角色。这样可以减少开发者的工作量,同时也使代码更加简洁明了。

总之,将@Controller、@Service和@Repository注解定义为@Component注解的别名,是为了让开发者在不同的场景下使用更加方便,同时也方便了Spring框架对不同类型的组件进行管理和扫描。

@Controller、@Service和@Repository在分层架构的应用中,使得可读性更强。

2.2 配置类

  • @Configuration 和 @Bean

在Spring框架中,@Configuration和@Bean注解通常一起使用,用于定义Spring应用中的Bean组件。

@Configuration注解标记一个类为配置类,表示这个类中定义了一些Spring Bean组件的配置信息。通常,在@Configuration注解的类中,使用@Bean注解定义各个Bean组件,这些组件可以是Java对象、第三方库对象或其他Spring组件。

@Bean注解表示一个方法会返回一个对象,该对象会被注册到Spring容器中,并可以被其他组件所引用。通常,在@Bean注解的方法中,通过Java代码或其他方式创建一个对象,并返回这个对象的实例。这个实例就是一个Spring Bean组件,可以被Spring框架管理和使用。

@Configuration和@Bean注解的组合,让开发者可以通过Java代码的方式,对Spring应用中的Bean组件进行配置和管理。相比XML配置方式,这种方式更加灵活,可以充分利用Java语言的优势,实现更加高效和可读性强的配置方式。

  • @ConfigurationProperties

@ConfigurationProperties是Spring Boot框架中的注解,它用于将配置文件中的属性值绑定到Java对象上。

通常情况下,在Spring Boot应用中,我们需要读取一些配置属性,如数据库连接信息、邮件服务器配置等。这些属性通常保存在application.properties或application.yml等配置文件中。使用@ConfigurationProperties注解,可以将这些属性值映射到一个Java对象上,方便我们在代码中进行访问和使用。

@ConfigurationProperties注解的使用步骤如下:

  1. 定义一个Java对象,并使用@Component或@Configuration注解将其注册到Spring容器中;
  2. 在Java对象上使用@ConfigurationProperties注解,指定属性的前缀,如:
@Component
@ConfigurationProperties(prefix = "myapp.db")
public class DatabaseConfig {
    private String url;
    private String username;
    private String password;
    // getters and setters
}
  1. 在配置文件中,添加对应的属性值,如:
myapp.db.url=jdbc:mysql://localhost:3306/myapp
myapp.db.username=root
myapp.db.password=123456

这样,在Spring Boot应用启动时,Spring框架会自动读取配置文件中的属性值,并将其绑定到DatabaseConfig对象上。我们可以通过@Autowired注解引用DatabaseConfig对象,并使用其中的属性值。

2.3 属性

  1. @Lazy:用于指定Bean的延迟初始化,即在首次使用时才进行初始化。
  2. @Primary:用于指定多个同类型的Bean中的首选项,当Spring无法确定使用哪个Bean时,会选择具有@Primary注解的Bean。
  3. @DependsOn:用于指定Bean之间的依赖关系,即指定一个Bean在另一个Bean之后进行初始化。
  4. 。。。

可以指定Bean的属性、作用域、初始化方式等,当然这些设置也可以在@Bean属性中指定,可以使用单独的注解指定。

3 选择性实例化Bean

在一个包中,我们有很多组件类,@Controller、@Service、@Repository和@component注解的类,但是因为业务需要,我们只需要一部分实例化,即加入容器管理,此时可以使用过滤器,来指定那些注解类需要实例化,那些注解不需要实例化。

我们把类放在一个文件中,仅做演示,实际中一般一个类一个单独文件。示例代码3-1如下所示:

package com.gaogzhen.spring6.bean2;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

/**
 * @author: Administrator
 * @createTime: 2023/02/26 09:28
 */
@Component
public class A {
    public A() {
        System.out.println("A 类无参构造方法");
    }
}

@Controller
class B {
    public B() {
        System.out.println("B 类的无参构造方法");
    }
}

@Service
class C {
    public C() {
        System.out.println("c 类的无参构造方法");
    }
}

@Repository
class D {
    public D() {
        System.out.println("d 类的无参构造方法");
    }
}

配置类做包扫描和过滤,如下嗲吗3-2所示:

package com.gaogzhen.spring6.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;

/**
 * @author gaogzhen
 */
@ComponentScans({
        @ComponentScan(basePackages = "com.gaogzhen.spring6.bean2",
                excludeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
                    @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Repository.class)})
})
@Configuration
public class PackageConfig {

}
  • excludeFilters:为指定排除过滤
  • includeFilters:为指定包含过滤

测试代码3-3如下所示:

@Test
public void testChooseInstantiation() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    context.register(PackageConfig.class);
    context.refresh();

    List<String> beanNames = Arrays.asList("a", "b", "c", "d");
    for (String beanName : context.getBeanDefinitionNames()) {
        if (beanNames.contains(beanName)){
            System.out.println("beanName: " + beanName);
            System.out.println("bean: " + context.getBean(beanName));
        }
    }
}

测试结果如下所示:

A 类无参构造方法
c 类的无参构造方法
beanName: a
bean: com.gaogzhen.spring6.bean2.A@768ccdc5
beanName: c
bean: com.gaogzhen.spring6.bean2.C@4c6daf0

结语

如果小伙伴什么问题或者指教,欢迎交流。

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/spring6-study

参考:

[1]Spring框架视频教程[CP/OL].P69-75.

[2]ChatGPT

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

gaog2zh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值