• 一步步从Spring Framework装配掌握SpringBoot自动装配


    Spring Framework模式注解

    模式注解是一种用于声明在应用中扮演“组件”角色的注解。如 Spring Framework 中的 @Repository 标注在任何类上 ,用
    于扮演仓储角色的模式注解。

    模式注解(角色注解)

    Spring Framework 注解 场景说明
    @Component 通用组件模式注解
    @Controller Web 控制器模式注解
    @Service 服务模式注解
    @Repository 数据仓储模式注解
    @Configuration 配置类模式注解

    在Spring中进行装配context:component-scan 方式

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-
    context.xsd">
    <!-- 激活注解驱动特性 -->
    <context:annotation-config />
    <!-- 找寻被 @Component 或者其派生 Annotation 标记的类(Class),将它们注册为 Spring Bean -->
    <context:component-scan base-package="com.imooc.dive.in.spring.boot" />
    </beans>
    

    在Spring中基于Java注解配置方式

    @ComponentScan(basePackages = "com.imooc.dive.in.spring.boot")
    public class SpringConfiguration {
    ...
    }
    

    实战:自定义模式注解

    @Component 模式注解具有“派生性”和“层次性”,我们能够自定义创建Bean注解

    第一步:自定义SpringBean注解

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface MyServiceAnnotation {
        String value() default "";
    }
    
    

    第二步:将注解作用在自定义Bean上

    @MyServiceAnnotation(value = "testBean")
    public class TestBean {
        
    }
    

    第三步:测试是否可以从Spring容器中获取到自定义Bean

    @SpringBootApplication
    public class Main {
        public static void main(String[] args) {
            ConfigurableApplicationContext run = SpringApplication.run(Main.class, args);
            TestBean testBean = run.getBean("testBean", TestBean.class);
            System.out.println("testBean" + testBean.toString());
            run.close();
        }
    }
    

    Spring Framework@Enable模块装配

    Spring Framework 3.1 开始支持”@Enable 模块驱动“。所谓“模块”是指具备相同领域的功能组件集合, 组合所形成一个独立的单元。比如 Web MVC 模块、AspectJ代理模块、Caching(缓存)模块、JMX(Java 管 理扩展)模块、Async(异步处理)模块等。

    @Enable 注解模块举例

    框架实现 @Enable 注解模块 激活模块
    Spring Framework @EnableWebMvc Web MVC 模块
    Spring Framework @EnableTransactionManagement 事务管理模块
    Spring Framework @EnableCaching Caching 模块
    Spring Framework @EnableMBeanExport JMX 模块
    Spring Framework @EnableAsync 异步处理模块
    Spring Framework @EnableWebFlux Web Flux 模块
    Spring Framework @EnableAspectJAutoProxy AspectJ 代理模块
    Spring Boot @EnableAutoConfiguration 自动装配模块
    Spring Boot @EnableManagementContext Actuator 管理模块
    Spring Boot @EnableConfigurationProperties 配置属性绑定模块
    Spring Boot @EnableOAuth2Sso OAuth2 单点登录模块
    ......

    @Enable实现方式

    • 注解驱动方式
    • 接口编程方式

    实战:自定义@Enable注解驱动实现方式

    第一步:实现自定义注解@EnableMyBean

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(MyBeanConfig.class)
    public @interface EnableMyBean {
    }
    

    PS:注意@Import(MyBeanConfig.class),将导入MyBeanConfig配置类的相关Bean

    第二步:创建MyBeanConfig配置类

    @Configuration
    public class MyBeanConfig {
        @Bean(name = "hello")
        public String hello() {
            return "word";
        }
    }
    

    第三步:在应用中测试使用@EnableMyBean

    @SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.three")
    @EnableMyBean
    public class Main {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(Main.class)
                            .web(WebApplicationType.NONE)
                            .run(args);
            String bean = context.getBean("hello", String.class);
            context.close();
    
        }
    }
    

    实战:自定义@Enable接口实现方式

    第一步:实现自定义注解@EnableMyBean

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(MyBeanConfigSelector.class)
    public @interface EnableMyBean {
    }
    

    PS:注意@Import(MyBeanConfigSelector.class)导入的类和@Enable注解驱动导入的不一样,这里导入的是一个实现了ImportSelector接口的类

    public class MyBeanConfigSelector implements ImportSelector {
    
    
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{new MyBeanConfig().getClass().getName()};
        }
    }
    

    PS:在MyBeanConfigSelector类中我们可以自定义复杂的逻辑,这里我们仅仅简单返回MyBeanConfig配置类。

    第三步:创建MyBeanConfig配置类

    @Configuration
    public class MyBeanConfig {
        @Bean
        public String hello() {
            return "word";
        }
    }
    

    第四步:在应用中测试使用@EnableMyBean

    @SpringBootApplication(scanBasePackages = "com.jimisun.learnspringboot.four")
    @EnableMyBean
    public class Main {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(Main.class)
                            .web(WebApplicationType.NONE)
                            .run(args);
            String bean = context.getBean("hello", String.class);
            context.close();
    
        }
    }
    

    PS:其实@Enable接口的实现方式和@Enable注解实现方式是基本一样的,只不过多了一个步骤,方便我们更灵活地进行编写逻辑。

    Spring Framework条件装配

    从 Spring Framework 3.1 开始,允许在 Bean 装配时增加前置条件判断

    Spring 注解 场景说明 起始版本
    @Profile 配置化条件装配 3.1
    @Conditional 编程条件装配 4.0

    实战:自定义@Profile 配置化条件装配

    第一步:自定义创建某服务不同的@Profile实现类

    public interface UserService {
        void println();
    }
    
    
    @Service
    @Profile("vip")
    public class VipUserservice implements UserService {
        @Override
        public void println() {
            System.out.println("I am VIP User");
        }
    }
    
    
    @Service
    @Profile("common")
    public class CommonUserservice implements UserService {
        @Override
        public void println() {
            System.out.println("I am Common User");
        }
    }
    

    第二步:在构建Spring容器指定配置

    @ComponentScan(basePackages = "com.jimisun.learnspringboot.two")
    public class Main {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext run = new SpringApplicationBuilder(Main.class).
                    web(WebApplicationType.NONE).
                    profiles("vip").
                    run(args);
            UserService bean = run.getBean(UserService.class);
            bean.println();
            run.close();
        }
    }
    
    

    实战:自定义@Conditional 编程条件装配

    第一步:创建一个自定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Documented
    @Conditional({MyOnConditionProperty.class})
    public @interface MyConditionOnPropertyAnnotion {
        String prefix() default "";
    }
    

    PS:注意@Conditional注解,将会找到MyOnConditionProperty类的matches方法进行条件验证

    第二步:创建该注解的条件验证类,该类实现Condition接口

    public class MyOnConditionProperty implements Condition {
    
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            Map<String, Object> annotationAttributes =
                    annotatedTypeMetadata.getAnnotationAttributes(MyConditionOnPropertyAnnotion.class.getName());
            String prefix = String.valueOf(annotationAttributes.get("prefix"));
            return prefix.equals("pass");
        }
    }
    

    第三步:在Spring应用中应用条件装配

    @SpringBootApplication
    public class Main {
    
    
        @Bean(name = "hello")
        @MyConditionOnPropertyAnnotion(prefix = "pass")
        public String hello() {
            return "word";
        }
    
        public static void main(String[] args) {
            ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(Main.class)
                            .web(WebApplicationType.NONE)
                            .run(args);
            String bean = context.getBean("hello", String.class);
            context.close();
    
    
        }
    }
    

    PS:本例自定义的MyConditionOnPropertyAnnotion在应用中装配的时候可以指定prefix值,该值将会在实现了Condition借口的matches进行条件验证,如果验证通过,则在Spring容器中装配该Bean,反之则不装配。

    SpringBoot 自动装配

    在 Spring Boot 场景下,基于约定大于配置的原则,实现 Spring 组件自动装配的目的。其中底层使用了一系列的Spring Framework手动装配的方法来构成Spring Boot自动装配。

    自定义SpringBoot自动装配

    1. 激活自动装配 - @EnableAutoConfiguration
    2. 实现自动装配 - XXXAutoConfiguration
    3. 配置自动装配实现 - META-INF/spring.factories

    第一步 :激活自动装配 - @EnableAutoConfiguration

    @EnableAutoConfiguration
    public class Main {
        public static void main(String[] args) {
            ConfigurableApplicationContext context =
                    new SpringApplicationBuilder(Main.class)
                            .web(WebApplicationType.NONE)
                            .run(args);
            String bean = context.getBean("hello", String.class);
            context.close();
    
        }
    }
    

    第二步:实现自动装配 - XXXAutoConfiguration

    @Configuration
    @EnableMyBean
    public class HelloWordAutoConfiguration {
    }
    

    PS:这里使用了上面我们创建的@EnableMyBean,这个注解会注入一个名为“hello"的Bean

    第三步:配置自动装配实现 - META-INF/spring.factories

    在ClassPath目录下创建META-INF文件夹再创建spring.factories文件

    #配置自己的自动装配Bean
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    com.jimisun.learnspringboot.five.HelloWordAutoConfiguration
    

    最后:运行测试第一步中的Main方法,看是否能获取到名为“hello”的Bean

    本章总结

    本章我们主要了解了Spring Framework的模式注解装配,@Enable装配和条件装配。对于SpringBoot的自动装配我们仅仅做了一下演示,遵循SpringBoot装配的三个步骤,我们就可以运行SpringBoot的自动装配。但是对于SpringBoot为什么要遵循这三个步骤?自动装配的原理?我们不知所以然,所以下一章节我们仍然以SpringBoot的自动装配为主题,对SpringBoot的底层源码做剖析。

    该教程所属Java工程师之SpringBoot系列教程,本系列相关博文目录 Java工程师之SpringBoot系列教程前言&目录

  • 相关阅读:
    金蝶中间件 前后台连不上 报跨域 前台解决方案: --user-data-dir="c:ChromeDebug" --test-type --disable-web-security
    chalk 库 console.info(chalk.blue('kkk'))
    让 js 失效 Chrome F12 右上角 settings
    openlayers.org 百度地图 静态化 同类产品
    vscode 自动格式化md文件,搞得很是郁闷,加入 [markdown] 自定义配置 "editor.formatOnSave": false 搞定了。
    electron vite2 vue3 安装 cvep my-electron-cvep
    baidu 突然打不开了 20210621
    vscode vue 鼠标Ctrl+单击 函数跳转 插件名称:vue-helper
    接口返回数据的属性值 不要返回数字0和1
    vscode 自动格式化 好使的配置 setting.json 20210622
  • 原文地址:https://www.cnblogs.com/jimisun/p/10070123.html
Copyright © 2020-2023  润新知