2021-07-17阅读小笔记:Spring之编程式驱动IOC

1、编程式驱动 IOC 有什么特点?

编程式更贴近于Spring的底层原理,不管是SpringBoot原理还是Spring集成第三方框架,都是可以利用编程式驱动来完成。

2、编程式驱动与声明式 / 配置式的关联是什么?

编程式因为是Spring的底层原理,所以它也是声明式与配置式在Spring的底层处理方式。

3、编程式实战

github代码地址:编程式驱动IOC

准备

抽象一个Animal类,接着有Cat、Dog和Rabbit三个子类

@Data
public abstract class Animal {
    private String name;
    private Person person;
}

public class Cat extends Animal{

    public Cat(){
        System.out.println("cat 初始化。。。。");
    }
}

public class Dog extends Animal{

    public Dog(){
        System.out.println("dog 初始化。。。。");
    }
}

public class Rabbit extends Animal{

    public Rabbit(){
        System.out.println("rabbit 初始化。。。。");
    }
}

3.1、手动生成&注入BeanDefinition

测试应用:

public class Application {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        // 注册person
        BeanDefinition personBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Person.class).getBeanDefinition();
        personBeanDefinition.getPropertyValues().addPropertyValue("name","laowang");
        context.registerBeanDefinition("laowang",personBeanDefinition);

        // 注册cat,如果是属性是需要注入其他Bean实例对象的,需要在 BeanDefinitionBuilder 构建 BeanDefinition 时完成,不然只能添加常量的属性值
        BeanDefinition catBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Cat.class)
                .addPropertyValue("name","small cat")
                .addPropertyReference("person","laowang")
                .getBeanDefinition();
        context.registerBeanDefinition("myCat",catBeanDefinition);

        // 注入dog,测试原型bean  ApplicationContext#refresh 方法执行时不会对myDog进行初始化,即不会构建原型Bean的实例,只有当获取Bean实例时才会开始初始化。
        BeanDefinition dogBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Dog.class)
                .addPropertyValue("name","small dog")
                .addPropertyReference("person","laowang")
                .setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
                .getBeanDefinition();
        context.registerBeanDefinition("myDog",dogBeanDefinition);

        // 注入rabbit,测试延迟加载 ApplicationContext#refresh 方法执行时不会对myRabbit进行初始化,即不会构建原型Bean的实例,只有当获取Bean实例时才会开始初始化。
        BeanDefinition rabbitBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Rabbit.class)
                .addPropertyValue("name","small rabbit")
                .addPropertyReference("person","laowang")
                .setLazyInit(true)
                .getBeanDefinition();
        context.registerBeanDefinition("myRabbit",rabbitBeanDefinition);

        // 因为没有传入配置类,需要手动刷新
        context.refresh();
        System.out.println("application context refreshed.....");
        Optional.ofNullable((Person) context.getBean("laowang")).ifPresent(System.out::println);
        Optional.ofNullable((Cat) context.getBean("myCat")).ifPresent(System.out::println);
        Optional.ofNullable((Dog) context.getBean("myDog")).ifPresent(System.out::println);
        Optional.ofNullable((Rabbit) context.getBean("myRabbit")).ifPresent(System.out::println);
        context.close();
    }
}

3.2、利用 ClassPathBeanDefinitionScanner 根据指定路径查找&注入BeanDefinition

测试应用:

public class ClassPathScanApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // ClassPathBeanDefinitionScanner 需要注入 BeanDefinitionRegistry
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext);
        // scanner 需要增加过滤条件,否则一个都扫描不出来
        scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> {
            // getClassMetadata可以获取到扫描类的相关元信息,此处把Animal的子类都拿出来
            // metadataReader 包含类元信息、注解元信息,所以我们可以联想到 @Component 等系列注解可以靠这个来完成注解注入组件
            return metadataReader.getClassMetadata().getSuperClassName().equals(Animal.class.getName());
        });
        /**
         * scan方法,会根据过滤器扫描到合适的类,然后生成BeanDefinitio并注入到IOC容器中
         */
        /*int beanDefinitionCount = scanner.scan("com.github.howinfun.demo.ioc.program");
        System.out.println("共扫描"+beanDefinitionCount+"个bean定义");*/

        /**
         * 返回所有符合扫描条件的BeanDefinition,但是这些BeanDefinition没有被注入到IOC容器中
         */
        Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents("com.github.howinfun.demo.ioc.program");
        // 手动注入
        beanDefinitions.stream().forEach(beanDefinition -> applicationContext.registerBeanDefinition(beanDefinition.getBeanClassName(),beanDefinition));
        // 手动调用refreshed
        applicationContext.refresh();
        System.out.println(applicationContext.getBean(Cat.class));
        System.out.println(applicationContext.getBean(Dog.class));
    }
}

3.3、XmlBeanDefinitionReader 扫描xml文件并注入BeanDefinition

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="laowang" class="com.github.howinfun.demo.ioc.program.Person">
        <property name="name" value="老王"/>
    </bean>
</beans>

测试应用:

public class XmlBeanDefinitionReaderApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();;
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(applicationContext);
        //reader.loadBeanDefinitions(new ClassPathResource("program/beans.xml"));
        reader.loadBeanDefinitions("program/beans.xml");
        applicationContext.refresh();
        System.out.println(applicationContext.getBean(Person.class));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值