随笔记录-看nacos源码

@Import注解

@Import注解可以导入一些配置类,也就是创建一些指定对象。

使用@Import导入普通类

在这里插入图片描述

项目结构中,import-consumer和import-provider都是同层级的module,import-consumer的pom文件中有引用import-provider的依赖;

import-provider中创建接口的实现类:ImportFirstWayProviderConfig

@Slf4j
public class ImportFirstWayProviderConfig implements ImportAnnotationAble{

    @PostConstruct
    public void init(){
         log.info("这是@Import注解第一种用法,直接导入普通类");
    }

    @Override
    public String introduce() {
        return "这是@Import注解第一种用法,直接导入普通类";
    }
}

import-consumer中创建注解 @TestImportAnnotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(value = {ImportFirstWayProviderConfig.class})
public @interface TestImportAnnotation {
}

import-consumer中任意一个@service中使用刚才创建的@TestImportAnnotation注解:

@Service
@TestImportAnnotation
public class ThreeImportService {

}

然后启动 import-consumer module:

在这里插入图片描述

可以发现启动的是import-consumer,但是成功将import-provider中ImportFirstWayProviderConfig类给创建了。

实现ImportSelector接口

在import-provider种,添加一个类: ImportSecondWayProviderConfig

@Slf4j
public class ImportSecondWayProviderConfig implements ImportAnnotationAble{


    @PostConstruct
    public void init(){
        log.info("这是@Import注解【第二种】用法,在消费module里实现ImportSelector接口");
    }

    @Override
    public String introduce() {
        return "这是@Import注解【第二种】用法,在消费module里实现ImportSelector接口";
    }
}

在import-consumer种,实现ImportSelector接口:ImportSecondWayImpl

public class ImportSecondWayImpl implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.example.importProvider.config.importWay.ImportSecondWayProviderConfig"};
    }
}

其中返回的字符串就是 ImportSecondWayProviderConfig 的全路径;在@TestImportAnnotation注解中添加:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(value = {ImportFirstWayProviderConfig.class, ImportSecondWayImpl.class})
public @interface TestImportAnnotation {
}

启动import-consumer项目:

在这里插入图片描述

可以看到也是成功加载了。

实现ImportBeanDefinitionRegistrar接口

在import-provider中添加 ImportThirdWayProvider 类:

@Slf4j
public class ImportThirdWayProvider implements ImportAnnotationAble{

    @PostConstruct
    public void init(){
        log.info("这是@Import注解《第三种》用法,在消费module里实现ImportBeanDefinitionRegistrar接口");
    }

    @Override
    public String introduce() {
        return "这是@Import注解《第三种》用法,在消费module里实现ImportBeanDefinitionRegistrar接口";
    }
}

在import-consumer中实现ImportBeanDefinitionRegistrar接口:

public class ImportThirdWayImpl implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition define = new RootBeanDefinition(ImportThirdWayProvider.class);
        registry.registerBeanDefinition("importThirdWay",define);
    }
}

在RootBeanDefinition的带参构造函数中,参数就是需要的ImportThirdWayProvider 对象,在@TestImportAnnotation注解中添加:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(value = {ImportFirstWayProviderConfig.class, ImportSecondWayImpl.class, ImportThirdWayImpl.class})
public @interface TestImportAnnotation {
}

启动项目:

在这里插入图片描述

@ConditionalOnProperty注解

新建一个注解 @ConditionToday:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ConditionalOnProperty(value = "today.isWorkDay", matchIfMissing = true)
public @interface ConditionToday {
}

新建一个注解修饰的类:

@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionToday
public class ConditionWorkBean {

    @PostConstruct
    public void init(){
        log.info("这是 ConditionWorkBean 的 init方法");
    }

}

在application.yml中添加配置:

today:
  isWorkDay: true

在spring.factories文件中增加这个类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.importConsuemer.bean.ConditionWorkBean

成功启动项目:

在这里插入图片描述

修改配置为false,再次启动项目,会发现并没有打印 日志,说明没有创建。

@Bean注解修饰方法

之前一直使用@Bean注解方法修饰无参的方法,在看NacosServiceRegistryAutoConfiguration源码的时候,发现修饰的是有参构造方法,好奇参数的值是怎么创建的。

创建两个普通对象 BeanAnnotationUse ,BeanAnnotationUse :

public class BeanHasCreated {
    private String name;

    public String getName() {
        return name;
    }
}

@Slf4j
public class BeanAnnotationUse {
    private String name;

    public String getName() {
        return name;
    }

    public BeanAnnotationUse(String name) {
        this.name = name;
    }

    public BeanAnnotationUse() {
    }

    public String test(){
        log.info("这是使用@Bean注解创建的bean的测试方法,输出的name={}",getName());
        return getName();
    }
}

再新增一个中间类,TestBeanAnnotation,并将这个类配置再spring.factories中。

@Slf4j
public class TestBeanAnnotation {

    @PostConstruct
    public void init(){
        log.info("这是测试 @Bean注解的初始化方法");
    }

    @Bean
    public BeanAnnotationUse beanAnnotationUse2(BeanHasCreated bhc){
        return new BeanAnnotationUse("@Bean修饰有参数的方法");
    }
}

编译有报错,并且启动项目也会报错,提示的很清楚:找不到BeanHasCreated这个对象,

在这里插入图片描述

@Configuration
public class BeanHasCreated {
    private String name;

    public String getName() {
        return name;
    }
}

在BeanHasCreated类上增加@Configuration注解,这个时候编译没报错,启动项目也正常,那就说明@Bean修饰的方法参数必须是已经在spring中注入过的bean。

ApplicationListener接口和ApplicationEventPublisher接口

ApplicationEventPublisher接口时spring提供的一个用来发布事件的接口,ApplicationListener接口时spring提供的一个用来订阅事件发布的接口。

ApplicationListener接口demo

新建一个订阅事件类:

@Configuration
@Slf4j
public class TestWebServerEventListener implements ApplicationListener<WebServerInitializedEvent> {
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        log.info("接收的容器启动事件的");
    }
}

然后直接启动项目,会发现打印结果符合预期。

在这里插入图片描述

使用@EventListener注解

在这里插入图片描述

自定义事件和自定义订阅

新建自定义事件对象:

public class TestSelfEvent extends ApplicationEvent {

    private String eventName;

    public TestSelfEvent(Object source) {
        super(source);
        this.eventName = "随便自定义的事件";
    }

    public TestSelfEvent(Object source, Clock clock) {
        super(source, clock);
    }

    @Override
    public String toString() {
        return "TestSelfEvent{" +
                "eventName='" + eventName + '\'' +
                '}';
    }
}

新建发布类:

@Slf4j
@Component
public class TestSelfPublisher implements ApplicationEventPublisher, ApplicationContextAware {

    private ApplicationContext context;

    @Override
    public void publishEvent(Object event) {
        log.info("准备发布一个事件:{}",event.toString());
        context.publishEvent(event);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}

新建订阅对象:

@Slf4j
@Configuration
public class SelfEventListener implements ApplicationListener<TestSelfEvent> {

    @Override
    public void onApplicationEvent(TestSelfEvent event) {
        log.info("接收到事件,内容是,event.getSource() = {}",event.getSource());
    }

}

再新建一个测试用的类:

@Configuration
@AutoConfigureAfter({TestSelfPublisher.class,SelfEventListener.class})
@Slf4j
public class TestSelfEventImport {


    @Autowired
    private  TestSelfPublisher tsp;

    @PostConstruct
    public void init(){
        TestSelfEvent tsf = new TestSelfEvent("这是一个自定义的随便的任意的一个事件");
        tsp.publishEvent(tsf);
    }

}

启动项目,打印如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值