专栏首页HUC思梦的java专栏springBoot @Enable*注解的工作原理

springBoot @Enable*注解的工作原理

使用注解实现异步

RunnableDemo类

package com.boot.enable.bootenable;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RunnableDemo implements Runnable {

    @Async // 异步方式执行方法
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("----------------"+ (i +1));
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试类

package com.boot.enable.bootenable;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class BootEnableApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                SpringApplication.run(BootEnableApplication.class, args);
        Runnable bean = context.getBean(Runnable.class);
        System.out.println("-----------start-----------");
        bean.run();
        System.out.println("-----------end-----------");

        context.close();
    }
}

运行结果分析:

run方法打印的内容是异步进行的,是独立于主线程外的线程,所以-----------end-----------打印后,run方法依然再进行打印

几种装配方式

1.普通的方式

package com.boot.enable.imp.demo;

public class Book {
}
package com.boot.enable.imp.demo;

import org.springframework.stereotype.Component;

@Component
public class User {
}
package com.boot.enable.imp.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;

/**
 * 普通方式装配
 */
@SpringBootApplication
public class ImportApplication {

    @Bean
    public Book book() {
        return new Book();
    }

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                SpringApplication.run(ImportApplication.class, args);
        System.out.println(context.getBean(User.class));
        System.out.println(context.getBean(Book.class));

        context.close();
    }
}

使用@Import装配的第一种方式

package com.boot.enable.imp.demo1;

public class Book {
}
package com.boot.enable.imp.demo1;

public class User {
}
package com.boot.enable.imp.demo1;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class BeanImportSelector implements ImportSelector {//不需要注入其他属性时使用
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.boot.enable.imp.demo1.Book"
                ,"com.boot.enable.imp.demo1.User"};
    }
}
package com.boot.enable.imp.demo1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

/**
 * 使用@Import方式装配
 */
@SpringBootApplication
// @Import({User.class, Book.class})
@Import(BeanImportSelector.class)
public class ImportApplication1 {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                SpringApplication.run(ImportApplication1.class, args);
        System.out.println(context.getBean(User.class));
        System.out.println(context.getBean(Book.class));

        context.close();
    }
}

使用@Import装配 第二种方式

package com.boot.enable.imp.demo2;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {//有属性注入时使用
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 创建构建器对象
        BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(User.class);
        BeanDefinition beanDefinition = bdb.getBeanDefinition();
        registry.registerBeanDefinition("user", beanDefinition);

        BeanDefinitionBuilder bdb1 = BeanDefinitionBuilder.rootBeanDefinition(Book.class);
        BeanDefinition beanDefinition1 = bdb1.getBeanDefinition();
        registry.registerBeanDefinition("book", beanDefinition1);
    }
}
package com.boot.enable.imp.demo2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;

/**
 * 使用@Import方式装配
 */
@SpringBootApplication
@Import(MyBeanDefinitionRegistrar.class)
public class ImportApplication1 {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                SpringApplication.run(ImportApplication1.class, args);
        System.out.println(context.getBean("user",User.class));
        System.out.println(context.getBean(Book.class));

        context.close();
    }
}

实例演示:注解注册监控器实现

实体类准备:

package com.boot.enable.sample.bean;

import org.springframework.stereotype.Component;

@Component
public class Person {
}
public class Person1 {
}
package com.boot.enable.sample.bean;

import org.springframework.stereotype.Component;

@Component
public class Person2 {
}
package com.boot.enable.sample.vo;

import org.springframework.stereotype.Component;

@Component
public class UserVO {
}

自定义一个注解(借用@Import机制)

package com.boot.enable.sample;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ScannerPackageRegistrar.class)
public @interface EnableScanner {
    String[] packages();
}
package com.boot.enable.sample;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Arrays;
import java.util.List;

public class ScannerPackageRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
        String[] attrs = (String[]) importingClassMetadata
                .getAnnotationAttributes(EnableScanner.class.getName())
                .get("packages");//获取到注解的packages属性
        List<String> packages = Arrays.asList(attrs);
        System.out.println(packages);
        BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(MyBeanDefinitionProcessor.class);
        bdb.addPropertyValue("packages", packages);//注入属性

        registry.registerBeanDefinition(MyBeanDefinitionProcessor.class.getName(), bdb.getBeanDefinition());//装配到Spring容器中

    }
}
package com.boot.enable.sample;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.util.List;

public class MyBeanDefinitionProcessor implements BeanPostProcessor {

    private List<String> packages;

    public List<String> getPackages() {
        return packages;
    }

    public void setPackages(List<String> packages) {
        this.packages = packages;
    }

    @Override//扫描出装配到容器中的类并打印出对应实例
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        for (String pack : packages) {

            if (bean.getClass().getName().startsWith(pack)) {
                System.out.println("instance bean:"+bean.getClass().getName());
            }
        }
        return bean;
    }
}

测试类

package com.boot.enable.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * 普通方式装配
 */
@SpringBootApplication
@EnableScanner(packages ={"com.boot.enable.sample.bean","com.boot.enable.sample.vo"}) // 启用监控扫描类的注解
public class ScannerPackageApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context =
                SpringApplication.run(ScannerPackageApplication.class, args);
        context.close();

        new ScannerPackageApplication().callFunction(new FunctionImpl());//回调演示
    }


    interface Function {
        void hello();
    }

    static class FunctionImpl implements Function {

        @Override
        public void hello() {
            System.out.println("调用了FunctionImpl->Hello方法");
        }
    }

    public void callFunction(Function fun) {
     //处理其他事 
        fun.hello();  //回调
     //处理其他事
    }
}

打印结果(打印出注入到Spring容器中的实例,Person1未加注解,所以未打印)

监控器流程图解

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • @SpringBootConfiguration注解

    HUC思梦
  • SpringBoot JDBC/AOP

    HUC思梦
  • 常用注解使用总结系列: @Order 注解

    HUC思梦
  • spring之order注解

    我们今天要分享的是spring框架提供的@Order注解的使用,估计这篇文章的阅读时间应该在二到三分钟之间就结束了。

    后端Coder
  • feign源码

    上面是一段feign的代码, 系统是如何通过feign, 将reduceStock方法转换成stock服务的接口调用的呢?

    用户7798898
  • springBoot 入门(四)—— 使用 纯注解方式的junit整合测试

    配置类——用来替换xml配置文件 其中的@ComponentScan ,可以加载多个包下spring管理的bean,每个用分号“”和逗号,隔开,如果没有组件...

    MickyInvQ
  • 实战:十分钟实现基于JWT前后端分离的权限框架

    面试过很多Java开发,能把权限这块说的清楚的实在是不多,很多人因为公司项目职责问题,很难学到这类相关的流程和技术,本文梳理一个简单的场景,实现一个基于jwt前...

    JAVA葵花宝典
  • SpringBoot 动态修改定时任务频率

    调试情况如下: 1.调用start 2.调用change,并传入0/3 * * * * * 3.调用stop

    软件测试君
  • 一起来学SpringBoot | 第十八篇:轻松搞定全局异常

    实际项目开发中,程序往往会发生各式各样的异常情况,特别是身为服务端开发人员的我们,总是不停的编写接口提供给前端调用,分工协作的情况下,避免不了异常的发生,如果直...

    battcn
  • 【SpringSecurity系列01】初识SpringSecurity

    ​ 用自己的话 简单介绍一下,Spring Security基于 Servlet 过滤器链的形式,为我们的web项目提供认证与授权服务。它来自于S...

    yukong

扫码关注云+社区

领取腾讯云代金券