1. 程式人生 > >springBoot @Enable*註解的工作原理

springBoot @Enable*註解的工作原理

圖解 tor def sys autoconf 屬性註入 erb ota efi

使用註解實現異步

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未加註解,所以未打印)

技術分享圖片

監控器流程圖解

技術分享圖片

springBoot @Enable*註解的工作原理