Java bean解析

一、IOC思想

https://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html

IOC理论的提出

       在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间。如何降低系统之间、模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson 1996年提出了IOC理论,用来实现对象之间的“解耦”,目前这个理论已经被成功地应用到实践当中。

IOC理论的含义

IOC提出的观点:借助于“第三方”实现具有依赖关系的对象之间的解耦

IOC的解释

在引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。

软件系统在引入IOC容器之后,这种情形就完全改变了。由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

依赖注入

2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

IOC优点

松耦合、灵活性、可维护

IOC缺点

生成对象的步骤变得复杂,增加学习成本;

运行效率有一定损耗;

大量配置工作;

IOC框架本身的成熟度会影响项目整体的进程;

二、xml方式配置bean

todo 补代码

https://www.cnblogs.com/ysmdbk/p/11398482.html

1.无参构造

构建一个学生类,添加属性及get,set方法,添加tostring方法

package com.gf.springboot.ioc.xml;

import java.util.List;

public class Student {
    private String name;
    private Integer age;
    private List<String> classList;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<String> getClassList() {
        return classList;
    }

    public void setClassList(List<String> classList) {
        this.classList = classList;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", classList=" + String.join(",",classList) +
                '}';
    }
}

定义一个xml文件,定义学生类的bean

<?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="student" class="com.gf.springboot.ioc.xml.Student">
        <property name="name" value="zhangsan"/>
        <property name="age" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>
</beans>

构建一个类调用学生类

package com.gf.springboot.ioc.xml;


public class HelloService {
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
        return student.toString();
    }
}

在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="student" class="com.gf.springboot.ioc.xml.Student">
        <property name="name" value="zhangsan"/>
        <property name="age" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">
        <property name="student" ref="student"/>

    </bean>
</beans>

测试类测试

package com.gf.springboot;

import com.gf.springboot.ioc.xml.HelloService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;

@SpringBootTest
@ContextConfiguration(locations = "classpath:ioc/demo.xml")
class SpringbootApplicationTests {

    @Autowired
    private HelloService helloService;

    @Test
    public void testHello(){
        System.out.println(helloService.Hello());
    }

}

2.有参构造

修改学生类,通过构造器注入

package com.gf.springboot.ioc.xml;

import java.util.List;

public class Student {
    private String name;
    private Integer age;
    private List<String> classList;

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<String> getClassList() {
        return classList;
    }

    public void setClassList(List<String> classList) {
        this.classList = classList;
    }

    @Override
    public String toString() {
        return "student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", classList=" + String.join(",",classList) +
                '}';
    }
}

修改xml文件,学生类bean的定义,添加constructor-arg标签

<?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="student" class="com.gf.springboot.ioc.xml.Student">
        <constructor-arg index="0" value="zhangsan"/>
        <constructor-arg index="1" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">
        <property name="student" ref="student"/>

    </bean>
</beans>

测试

3.静态工厂方法

https://www.jianshu.com/p/ceb5ec8f1174

定义父类(animal类),子类(dog类,cat类),工厂类(animalfactory类)

package com.gf.springboot.ioc.xml;

public abstract class Animal {
    abstract String getName();
}
package com.gf.springboot.ioc.xml;

public class Dog extends Animal {
    @Override
    String getName() {
        return "dog";
    }
}
package com.gf.springboot.ioc.xml;

public class Cat extends Animal{
    @Override
    String getName() {
        return "cat";
    }
}
package com.gf.springboot.ioc.xml;

public class AnimalFactory {
    public static Animal getAnimal(String type) {
        if ("dog".equals(type)) {
            return new Dog();
        } else {
            return new Cat();
        }
    }
}

xml文件中定义两个子类的bean

<?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="student" class="com.gf.springboot.ioc.xml.Student">
        <constructor-arg index="0" value="zhangsan"/>
        <constructor-arg index="1" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">
        <property name="student" ref="student"/>
    </bean>

    <bean id="dog" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-method="getAnimal">
        <constructor-arg value="dog"/>
    </bean>

    <bean id="cat" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-method="getAnimal">
        <constructor-arg value="cat"/>
    </bean>
</beans>

构建一个类调用动物类

package com.gf.springboot.ioc.xml;


public class HelloService {
    private Student student;

    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
        return animal.getName();
    }
}

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="student" class="com.gf.springboot.ioc.xml.Student">
        <constructor-arg index="0" value="zhangsan"/>
        <constructor-arg index="1" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">
        <property name="student" ref="student"/>
        <property name="animal" ref="dog"/>
    </bean>

    <bean id="dog" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-method="getAnimal">
        <constructor-arg value="dog"/>
    </bean>

    <bean id="cat" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-method="getAnimal">
        <constructor-arg value="cat"/>
    </bean>
</beans>

测试类测试

4.实例工厂方法

修改animalfactory类,去掉static

package com.gf.springboot.ioc.xml;

public class AnimalFactory {
    public Animal getAnimal(String type) {
        if ("dog".equals(type)) {
            return new Dog();
        } else {
            return new Cat();
        }
    }
}

修改xml文件,添加工厂bean,并修改dog,cat的bean,添加属性factory-bean

<?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="student" class="com.gf.springboot.ioc.xml.Student">
        <constructor-arg index="0" value="zhangsan"/>
        <constructor-arg index="1" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">
        <property name="student" ref="student"/>
        <property name="animal" ref="cat"/>
    </bean>

    <bean id="animalFactory" class="com.gf.springboot.ioc.xml.AnimalFactory"/>

    <bean id="dog" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-bean="animalFactory" factory-method="getAnimal">
        <constructor-arg value="dog"/>
    </bean>

    <bean id="cat" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-bean="animalFactory" factory-method="getAnimal">
        <constructor-arg value="cat"/>
    </bean>
</beans>

测试类测试

优点

低耦合、对象关系清晰、集中管理

缺点

配置繁琐、开发效率稍低、文件解析耗时

三、注解方式配置bean

1.@Component声明

将xml中的bean定义注释掉,并在相应的类上添加@Component注解,在测试类中引用就可以发现并且不报错

package com.gf.springboot.ioc.xml;

import org.springframework.stereotype.Component;

@Component
public class HelloService {
    private Student student;

    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
        return "hello";
//        return animal.getName();
    }
}
<?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="student" class="com.gf.springboot.ioc.xml.Student">
        <constructor-arg index="0" value="zhangsan"/>
        <constructor-arg index="1" value="13"/>
        <property name="classList" >
            <list>
                <value>math</value>
                <value>english</value>
            </list>
        </property>
    </bean>

<!--    <bean id="helloService" class="com.gf.springboot.ioc.xml.HelloService">-->
<!--        <property name="student" ref="student"/>-->
<!--        <property name="animal" ref="cat"/>-->
<!--    </bean>-->

    <bean id="animalFactory" class="com.gf.springboot.ioc.xml.AnimalFactory"/>

    <bean id="dog" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-bean="animalFactory" factory-method="getAnimal">
        <constructor-arg value="dog"/>
    </bean>

    <bean id="cat" class="com.gf.springboot.ioc.xml.AnimalFactory" factory-bean="animalFactory" factory-method="getAnimal">
        <constructor-arg value="cat"/>
    </bean>
</beans>
package com.gf.springboot;

import com.gf.springboot.ioc.xml.HelloService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;

@SpringBootTest
//@ContextConfiguration(locations = "classpath:ioc/demo.xml")
class SpringbootApplicationTests {

    @Autowired
    private HelloService helloService;

    @Test
    public void testHello(){
        System.out.println(helloService.Hello());
    }

}

2.配置类中使用@Bean

使用注解来实现子类bean定义,需要新建一个BeanConfiguration类添加@Configuration注解,定义子类并添加@Bean注解

package com.gf.springboot.ioc.ann;

import com.gf.springboot.ioc.xml.Animal;
import com.gf.springboot.ioc.xml.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfiguration {
    @Bean("dog")
    Animal getDog(){
        return new Dog();
    }
}

在测试类中引用并测试

package com.gf.springboot.ioc.xml;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HelloService {
    private Student student;

    @Autowired
    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
//        return "hello";
        return animal.getName();
    }
}

3.继承FactoryBean

新建一个类实现类型为animal的FactoryBean,添加@Component注解,实现它的方法

package com.gf.springboot.ioc.ann;

import com.gf.springboot.ioc.xml.Animal;
import com.gf.springboot.ioc.xml.Cat;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component
public class MyCat implements FactoryBean<Animal> {

    @Override
    public Animal getObject() throws Exception {
        return new Cat();
    }

    @Override
    public Class<?> getObjectType() {
        return Animal.class;
    }
}

在测试类中需要用@Qualifier注解指定哪一个实现类,测试

package com.gf.springboot.ioc.xml;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class HelloService {
    private Student student;

    @Autowired
    @Qualifier("myCat")
    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
//        return "hello";
        return animal.getName();
    }
}

4.继承BeanDefinitionRegistryPostProcessor

新建一个类实现BeanDefinitionRegistryPostProcessor接口,添加注解,实现需要重写的方法

重写postProcessBeanDefinitionRegistry方法

package com.gf.springboot.ioc.ann;

import com.gf.springboot.ioc.xml.Monkey;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class MyBeanRegister implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Monkey.class);
        registry.registerBeanDefinition("monkey",rootBeanDefinition);

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
package com.gf.springboot.ioc.xml;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class HelloService {
    private Student student;

    @Autowired
    @Qualifier("monkey")
    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
//        return "hello";
        return animal.getName();
    }
}

5.继承ImportBeanDefinitionRegistrar

新建一个类实现ImportBeanDefinitionRegistrar接口,重写对应方法,方式和方法4一致

package com.gf.springboot.ioc.ann;

import com.gf.springboot.ioc.xml.Bird;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

@Component
public class MyBeanImport implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(Bird.class);
        registry.registerBeanDefinition("bird",rootBeanDefinition);
    }
}
package com.gf.springboot.ioc.xml;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class HelloService {
    private Student student;

    @Autowired
    @Qualifier("bird")
    private Animal animal;

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String Hello() {
//        return "hello";
        return animal.getName();
    }
}

在测试类指定实现类名称

package com.gf.springboot;

import com.gf.springboot.ioc.ann.MyBeanImport;
import com.gf.springboot.ioc.xml.HelloService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;

@SpringBootTest
//@ContextConfiguration(locations = "classpath:ioc/demo.xml")
@Import(MyBeanImport.class)
class SpringbootApplicationTests {

    @Autowired
    private HelloService helloService;

    @Test
    public void testHello(){
        System.out.println(helloService.Hello());
    }

}

优点

使用简单、开发效率高、高内聚

缺点

配置分散、对象关系不清晰、配置修改需要重新编译工程

四、refresh方法解析

bean配置读取加载入口,spring框架启动流程,面试重点

子方法调用

prepareRefresh方法:刷新上下文之前做一个准备

容器状态设置

初始化属性设置

检查必备属性是否存在

obtainFreshBeanFactory方法:获取bean工厂

设置beanFactory序列化id

获取beanFactory

prepareBeanFactory方法:对beanFactory进行配置

设置beanFactory一些属性

添加后置处理器

设置忽略的自动装配接口

注册一些组件

postProcessBeanFactory方法:注册web请求,相关的处理器和bean以及配置

子类重写以在BeanFactory完成创建后做进一步设置

invokeBeanFactoryPostProcesses方法

   

调用BeanDefinitionRegistryPostProcessor实现向容器内添加bean的定义

调用BeanFactoryPostProcessor实现向容器内bean的定义的添加属性

registerBeanFactoryPostProcessors方法

找到BeanPostProcessor的实现

排序后注册进容器内

initMessageSource方法

初始化国际化相关属性

initApplicationEventMulticaster方法

初始化事件广播器

onRefresh方法

创建web容器

registerListeners方法

添加容器内事件监听器至事件广播器中

派发早期事件

finishBeanFactoryInitialization方法

初始化所有剩下的单实例bean

finishRefresh方法

初始化生命周期处理器

调用生命周期处理器onRefresh方法

发布ContextRefreshedEvent事件

JMX相关处理

resetCommonCaches方法

事后清理缓存

五、refresh方法中bean实例化解析

spring容器是如何初始化单例bean

还有再多看几遍视频加深理解~~~

太难了~~

BeanDefinition介绍

一个对象在Spring中描述,RootBeanDefinition是其常见实现

通过操作BeanDefinition来完成bean实例化和属性注入

BeanDefinition类图

自定义创建bean

六、总结

介绍一下IOC思想?

springboot中bean有哪几种配置方式?分别介绍一下。

bean的配置你喜欢哪种方式,为什么?

介绍下refresh方法流程

请介绍一个refresh中你比较熟悉的方法说出其作用?

介绍下bean实例化的流程?

说几个bean实例化的扩展点及其作用?

 


补充学习:静态工厂模式,单例模式,反射机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值