SpringBoot中的注解介绍

SpringBoot注解使用

1.@Configuration + @Bean

【比xml配置而言类更好维护、分类和管理阅读】 代理

1.1@Configuration的类就成为了"配置类",【取代application.xml文件】 @Configuration(proxyBeanMethods=true)默认单例,false获取到对象每次不同

总结:

Spring 会创建CGLIB 代理,保证 **@Bean 方法互相调用时,永远返回同一个单例 Bean**。

1.2方法public User getName()上加上@Bean注解【@Bean(name="abc")】对象为abc,无name属性值,则对象为getName\方法名 [取代application.xml中的<bean>标签]

总结:

  1. 首选 namevalue 属性 :如果写了 @Bean(name="abc"),Bean 的唯一标识就是 abc
  2. 默认使用方法名 :如果没有指定 name,Spring 会直接取方法名 getName 作为 Bean 的 ID
  3. 用来替代传统的 <bean id="abc" class="...User"> 配置

2.@Import() 导入组件

底层是一个接口 ()里面的参数是: Class<?>[] value() 【把 普通类 / 配置类 / ImportSelector 导入到spring的IOC容器中去,导入之后我们就可以直接从容器中拿】

特点:常用于第三方类、自动配置

java 复制代码
@Configuration
@Import(User.class, OrderConfig.class) // 直接导入多个组件
public class AppConfig {}

3.@ImportResource()导入资源文件( 老xml配置文件 )

以前的xml配置文件的形式编写配置,但是此注解将其注入IOC容器

作用:把传统 xml 配置文件加载进 Spring

**场景:**兼容老项目、遗留 XML

java 复制代码
@Configuration
@ImportResource("classpath:spring-context.xml")
public class XmlConfig {}

4.@ConditionalOnBean() 条件装配

作用: 容器里有某个 Bean 时,才创建当前 Bean

java 复制代码
@Configuration
public class ConditionConfig {
    @Bean
    @ConditionalOnBean(User.class) // 有User才注册Order
    public Order order() {
        return new Order();
    }
}

5.前四个注解大致总结:

@Import / @ImportResource / @Conditional 系列注解

都属于「配置类专用注解」,必须标注在 @Configuration 类上才会生效!

6.@ConfigurationProperties

作用:配置绑定 [自动把 application.yml / application.properties 里的配置项批量注入到 JavaBean\Java 类的属性中。]

java 复制代码
/**
 * 
 * 简单粗暴理解:把当前类丢到Ioc容器中去
 */
@Component //表明当前类是一个组件 {只有在容器中的组件,才会拥有SpringBoot提供的强大功能,加注解放入容器}  不代理
@ConfigurationProperties(prefix = "car1")    // 这个car1就是properties中配置的car对象的键值对,如:car1.brand=BYD car1.price=123
// 这样car需要的属性会和properties中的自动对应
@Data  // 没有手Setter 方法,@ConfigurationProperties 无法把配置文件里的值注入到成员变量中。
public class Car {
 private String brand;
    private Integer price;
}

ConfigurationProperties 的底层逻辑是通过 Java 反射调用 Setter 方法 (如 setBrand)来完成赋值的。如果类中只有私有属性而没有对应的 Setter,Car对象中属性值null
注意 :@ConfigurationProperties(prefix = "test.test1") 若找不到prefix前缀时,对象Car创建时bean名称改为:test.test1-cn.stylefeng.guns.tenant.modular.Cat #

  • 类所在的包在 @SpringBootApplication 的扫描路径下,否则 @Component 不会生效。

7.@Confinguration @Commponent 不同

  • @Component :如果这个类只是一个纯粹的 POJO 数据载体,或者仅仅是用来承载配置属性,不涉及复杂的 Bean 组装 。每次调用都会 new 一个新对象 ,单例直接失效!

  • @Configuration :如果你打算在这个类里定义多个有依赖关系的 @Bean(例如 Bean A 的创建需要调用 Bean B 的方法),则必须使用它 。是配置类 ,Spring 会创建CGLIB 代理 ,保证 **@Bean 方法互相调用时,永远返回同一个单例 Bean**。
    不要迷惑单例原因?从 Spring 容器中获取已创建好的 Bean

    java 复制代码
    @Configuration
    public class MyConfig {
    
        @Bean
        public User user() {
            return new User();
        }
    
        @Bean
        public Order order() {
            // 无论调用多少次 user(),永远返回同一个Bean
            return new Order(user());
        }
    }

8.@EnableConfigurationProperties

与@Configuration,@Component等配合使用\~!

理解: 当多个bean被@ConfigurationProperties()注解修饰,不愿再每个加@Component时,此注解就牛了
作用: 适合导入第三方配置,[第三方的配置没有用自动装配的相关注解,即没丢到IOC容器中,开发人员无法使用!此注解解决!!!]

1、开启属性配置绑定功能( 如:例子中的绑定Car类的属性 )使 @ConfigurationProperties 注解生效!

2、把组件自动注册到容器中( 如:例子中的Car,用了这个注解就可以把Car丢到Ioc容器中去 )

注意:@EnableConfigurationProperties 本身作用1.使@ConfigurationProperties修饰的po类与XXX.properties动态绑定2.将po类交由IOC容器管理!!!

但是要明白:@EnableConfigurationProperties 本身的类的前提是在IOC容器中,不然Spring如何读取。故【@Configuration 常用 @Component也可以但不多,@Service等也可以,很少用罢了,违背spring的设计语义】

java 复制代码
@Configuration
@EnableConfigurationProperties(Car.class)
public class MyConfig {

}
//===========另一个Car则是
//@Component  此注解不再需要
@ConfigurationProperties(prefix = "car1")   
@Data 
public class Car {
 private String brand;
    private Integer price;
}
java 复制代码
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
        ThreadFactory oneFactory = new ThreadFactoryBuilder().setNameFormat("one-pool-%d").build();

        return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(1000),
                oneFactory ,
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

}

类MyConfig中无@Bean注解,代理完全用不上,可改为@Component
总结: @EnableConfigurationProperties 只关心所在的类是不是一个 Spring Bean(在 IOC 里)。但是呢 类似ThreadPoolConfig 内部有@Bean注解,会有调用出现。所以不可改为@Component 。

9.ImportSelector

Spring 中用于 动态、条件化导入配置类 的核心接口

Spring Boot 自动配置(@EnableAutoConfiguration) 的底层灵魂

与 @Import 对比

  • 静态 @Import(XXX.class):编译时就写死要导入的类。
  • ImportSelector运行时 通过代码逻辑(判断环境、配置、类存在与否)动态决定导入哪些类。
java 复制代码
package org.springframework.context.annotation;

public interface ImportSelector {

    /**
     * 核心方法:返回需要导入的类的**全限定名数组**
     * @param importingClassMetadata 被@Import标注的类的所有注解信息(可读取注解属性)
     * @return 要导入的@Configuration类/组件的全类名数组
     */
    String[] selectImports(AnnotationMetadata importingClassMetadata);
}

执行时机(非常重要)

selectImports 方法在 Spring 容器启动、Bean 实例化之前 被调用。

  • 时机:早于 @Bean@ComponentScan
  • 作用:决定哪些类会被注册成 BeanDefinition ,进而实例化为 Bean
  • 当 Spring 解析到 @Import(YourSelector.class) 注解时,会立即 实例化 YourSelector 并调用其 selectImports() 方法。
  • 特点 :它的执行优先级非常高,发生在处理当前配置类中的 @Bean@ImportResource 等其他注解之前 。因此,在 selectImports() 方法中,你无法感知到由 @Bean 定义的 Bean。

DeferredImportSelector\后执行 接口方式 【主要用于动态获取bean @Import注解场景】

两者区别:

特性 ImportSelector DeferredImportSelector
执行时机 立即执行,在解析配置类时触发。 延迟执行,在所有配置类处理完毕后触发。
感知范围 无法感知 @Bean 定义的 Bean。 可以感知所有已加载的 Bean 定义和配置。
主要用途 根据简单条件(如注解属性)动态导入配置。 根据完整的上下文信息(如某个 Bean 是否存在)进行更复杂的动态导入。
排序支持 不支持。 支持通过 @OrderOrdered 接口排序。
java 复制代码
        3.1.//定义实现类实现接口ImportSelector
public class MyImportSelector implements DeferredImportSelector {
    @Override public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{MyConfiguration1.class.getName(), MyConfiguration2.class.getName(),
            MyConfiguration3.class.getName()};
    }
}//注意:String[] selectImports 方法内可以根据开发者逻辑返回不同类的全限定名!!
        3.2//在配置类上导入实现类
@Configuration
@Import(MyImportSelector.class)
public class MyConfiguration {
   @Bean
    public Object test() {
        log.info("MyConfiguration create a object bean...");
        return new Object();
    }
}
        3.3配置类样式
@Slf4j
public class MyConfiguration3 {
    public MyConfiguration3() {
        log.info("MyConfiguration3 construct...");
    }

    public void execute() {
        log.info("MyConfiguration3 execute...");
    }
}
3.4 调用
@SpringBootApplication
public class XXApplication{
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
        
        // 直接获取动态导入的Bean
        MyConfiguration3 myService = ctx.getBean(MyConfiguration3.class);
        myService.execute();
    }
}
  • MyConfiguration create a object bean...
  • MyConfiguration1 construct...
  • MyConfiguration2 construct...
  • MyConfiguration3 construct...
  • MyConfiguration3 execute...

原因:Spring 首先解析 MyConfiguration 类。虽然发现了 @Import,但因为它是 DeferredImportSelector,Spring 会先搁置它,转而去注册当前类中定义的 test() Bean。因此,@Bean 方法会最先执行。

类似场景:ImportBeanDefinitionRegistrar 接口方式 [定义注册器]

#扩展:AnnotationMetadata这个类 [做一个分布式任务调度的框架,如果结合springboot,那么在做一些自定义配置的时候就好很多]

1.定义注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import(MyHttpDeferredImportSelector.class)

public @interface MyHttp {

String name() default "";

String value() default "";

}

2.注解实现类

@Slf4j

public class MyHttpDeferredImportSelector implements DeferredImportSelector {

@Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {

importingClassMetadata.getAllAnnotationAttributes(MyHttp.class.getName(),true)

.forEach((k,v) -> {

log.info(importingClassMetadata.getClassName());

log.info("k:{},v:{}",k,String.valueOf(v));

});

return new String[0];

}//结果 MyConfiguration1全类名, name:myc1, MyConfiguration1全类名, value:myc1-value

}

3.使用注解

@Slf4j

@MyHttp(name = "myc1",value = "myc1-value")

public class MyConfiguration1 {

public MyConfiguration1() {

log.info("MyConfiguration1 construct...");

}

public void execute() {

log.info("MyConfiguration1 execute...");

}

}

相关推荐
一勺菠萝丶2 小时前
管理后台使用手册在线预览与首次登录引导弹窗实现
java·前端·数据库
小村儿2 小时前
连载05-Claude Skill 不是抄模板:真正管用的 Skill,都是从实战里提炼出来的
前端·后端·ai编程
无巧不成书02182 小时前
Java包(package)全解:从定义、使用到避坑,新手零基础入门到实战
java·开发语言·package·java包
身如柳絮随风扬2 小时前
SpringMVC 异常处理?Spring 父子容器?
java·spring·mvc
光电大美美-见合八方中国芯2 小时前
用于无色波分复用光网络的 10.7 Gb/s 反射式电吸收调制器与半导体光放大器单片集成
网络·后端·ai·云计算·wpf·信息与通信·模块测试
鬼先生_sir2 小时前
Spring AI Alibaba 用户使用手册
java·人工智能·springai
有梦想的小何2 小时前
从0到1搭建可靠消息链路:RocketMQ重试 + Redis幂等实战
java·redis·bootstrap·rocketmq
大数据新鸟2 小时前
HashMap、Hashtable、ConcurrentHashMap 核心对比
java
MX_93592 小时前
Spring MVC拦截器
java·后端·spring·mvc