Spring Bean的加载过程以及一些生命周期

Spring作为应用很广泛的开源框架,在面试中肯定少不了
Bean作为我们Spring的一大核心(容器)是非常重要的,下面是自己看周瑜老师学的还有其他一些视频的学习笔记
说一下Bean的加载过程,生命周期 (肯定少不了重要的IOC)
class———>推断构造方法———–>实例化——>对象——> 属性填充(IOC)——>初始化——->AOP------>Bean(这里没总结完)
bean的加载过程
Spring Bean的加载过程以及一些生命周期_第1张图片
我是这样理解的,从配置文件加载或者组件注解加载我们的Bean的时候会先进入一个叫BeanDefinition中,它是一个Map类型,主要是读取我们的Bean定义信息,注意这个时候我们的Bean中属性并没有进行赋值操作,然后图中的几个接口很重要,一个是Bean工厂,还有两个以Processor结尾的接口,我是这样理解的,他就是来修饰扩展我们的Bean的也可以说是增强我们的Bean,
Spring作为一个框架,必须要有一定的可扩展性,这个Processor就是让我们自定义我们的扩展组件的

总结:作为一个框架,首先要考虑我们的扩展性

Spring提供了什么扩展性

1.在对象创建之前我们可以欠佳某些功能

2.在容器初始化之前添加某些功能

3.在不同的阶段发出不同的时间,完成一些功能

4.抽象出一堆的接口来帮助扩展

FactoryBean中3个方法,是用来根据我们自己的想法步骤去创建出我们想要的Bean的;也就是说这一步肯定要先把Bean定义读取到BeanDefinitionReader的Map结构中,然后Spring提供的增强方法去修饰它,
构造工厂图中也表示出来了,可以看出是根据构造函数来实例化对象的,那么是怎么个原理呢?
推断构造方法,Spring如何判断构造函数来实例化对象
UserService是一个Bean,里面既有默认的无参构造函数,又有一个有参的构造函数(随便就行),那么它是怎么进行实例化的

答案是我们的Spring会调用我们的无参构造函数,我想让Spring用带参构造方法怎么办呢?

我们可以在有参构造函数方法上加@AutoWired注解

如果有两个带参的构造方法,就会报错,因为Spring不知道要用那个构造方法,会爆出No default constructor found

我们Spring对带参 的构造函数的参数是通过byType,byName的顺序一起匹配来找的,这里要区分单例Bean(单例池中)和单例模式的区别(有兴趣的可以看看)

只通过名字:那么我们找到的这个对象有可能跟我们的入参类型不匹配

只通过类型:要是我们的单例池中有好几个OrderService呢?不知道选哪一个
IOC DI 依赖注入
属性填充
**@AutoWired值怎么来的呢?**还是通过buType 和byName来的

AutowiredAnnotationBeanPostProcessor

1.先找注入点(这个类哪里加@AutoWired注解了)

根据我们的byType来找,在根据byName
Spring Bean的加载过程以及一些生命周期_第2张图片
@Resource注解

CommonAnnotationBeanPostProcessor

首先也会去寻找被@Resource注解了的方法和属性

1.如果@Resource注解指定了name属性,就直接从Spring容器拿对应的Bean,如果不存在则表示没有找到注入对象(报错)

2.如果@Resource注解没有指定了name属性,但是根据属性名字或setXXX中的**xxx在Spring容器中有对应的Bean,(不是根据参数名字找的)**那也直接根据名字拿

3.否则根据注入点Type类型去找Bean

那么怎么把值赋值进去呢?
反射
这里我只写了一个简单的例子,实际上肯定会比较复杂,但是意思就是这么个意思,只是少了很多逻辑,动态改变这些,看明白意思就行
代码准备
UserServiceImpl代码

public class UserServiceImpl {

}

UserController代码

public class UserController {
    //这只是声明了引用,并没有new对象
    //@AutoWired是怎么实现的呢?
    //spring的就是反射来实现的
    //我自己写一个
    @AutoWired//这是我自己写的
    private UserServiceImpl userServiceImpl;
    
    public UserServiceImpl getUserServiceImpl(){
        return userServiceImpl;
    }
}

实现@Autowired功能

/**
 * @author 王xx
 * @version 1.0
 * @date 20xxx 22:45
 * @Description TODO
 * @pojectname 自己实现我们的@AutoWired功能
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//作用在属性字段上
@Inherited
@Documented

public @interface AutoWired {
}

下面就是我们怎么样通过反射的方式,实现我们的Autowired功能,将我们的UserServiceImpl对象,赋值给我们的UserController

 //测试我们自己写的注解,也是我们IOC怎么实现的核心
    @Test
    public void testAutoWired(){
        UserController userController = new UserController();
        //获取Class对象
        Class<? extends UserController> aClass = userController.getClass();
        //获取所有属性值
        Stream.of(aClass.getDeclaredFields()).forEach(field -> {
            //获取属性名
            String name = field.getName();
            //获取属性名上的注解信息
            AutoWired annotation = field.getAnnotation(AutoWired.class);
            //判断我们的属性名是否备注解
            if (annotation != null){
                //设置访问属性
                field.setAccessible(true);
                //获取我们属性的类型,得到要注入的目标值
                Class<?> type = field.getType();
                //创建我们的注入对象的实例
                try {
                    Object o = type.newInstance();
                    //为我们的UserController注入对象
                    field.set(userController,o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        });
        System.out.println(userController.getUserServiceImpl());
    }

初始化
这里的初始化指的是我们的类中可能还有没有被@Autowired注解的属性,普通属性,怎么初始化呢?
eg:

public class UserService{
    @AutoWired
    private OrderService orderService;
	//我们没用注解标识,不会通过反射去动态的为其注入依赖
    private User defaultuser;
}

让我们的这个类实现我们的InitializingBean接口,并重写他的方法,这个方法就是在我们的属性注入之后来进行这个类的初始化的

public class UserService implements InitializingBean{
    @AutoWired
    private OrderService orderService;
	//我们没用注解标识,不会通过反射去动态的为其注入依赖
    private User defaultuser;
    @Override
	public void afterPropertiesSet() throws Exception {
	    //我们可以设置我们的逻辑
	    //比如从数据库查数据在给我们的默认user赋值
	    defauteUser = new User(xxxx);
	}
}

或者使用他的注解**@PostConstruct**,表明我们这个方式是个初始化的方法

初始化完成后,就看看我们是否有AOP的支持
比如我们的UserService的其中一个方法需要AOP支持,那么我们的Spring就会用CGLB代理生成一个UserServiceProxy的代理对象,但是需要注意的是,我们的这个UserServiceProxy中的有些属性是没有值的!!!(小坑)

public class UserService {
    @AutoWired
    private OrderService orderService;
    
    public void test(){
        //xxxxxxxxx
    }
}

实际上我们产生的代理类是这样的(模拟的)

class UserServiceProxy extend UserService{
    //目标对象
    private UserService target;
    
    public void test(){
        //先执行我们的代理逻辑
        //我这里想表达的就是只有一个前置方法
        //也就是我们的切面Bean的那个增强方法(我是这样理解的)
        UserServiceAspect.testBefore();
        //然后执行我们的目标方法
        target.test();
        //有可能还有后置方法,我这就不写了
    }
}

我们的代理类生成了一个目标对象,而且这个目标对象里也有一个OrderService对象,为啥为空?

我们的这个AOP逻辑处理的时候,我们是不会在进行属性注入的,就不会回去了,但是,我们的这个UserServiceProxy里面其实是有一个UserService对象的,而且我们点开这个对象发现,它里面的OrderService对象是有值的。
其余的还没总结完,下次聊

你可能感兴趣的:(java框架笔记,spring,ioc,bean,bean加载过程,bean生命周期)