八股文8:Spring

文章目录

什么是Spring

在这里插入图片描述

Spring由哪些模块组成(以Spring4为例)

在这里插入图片描述
在这里插入图片描述
Spring core中:框架的基本组成部分,包括控制反转和依赖注入
在这里插入图片描述

在这里插入图片描述

Spring IOC(控制反转)

在这里插入图片描述
在这里插入图片描述

Spring IOC 的实现原理

工厂机制+反射原理
在这里插入图片描述

我悟了:知道为啥我们pojo包的类不用注入吗??因为一般业务中一般我们都是自己创建对象(困扰了我好多天!!!,要不然难道你构造一个class都要注入,这spring容器会爆掉吧!!)
在这里插入图片描述

OrderEntity是没有注入的类

在这里插入图片描述

简单实现与应用+理解

在这里插入图片描述

在这里插入图片描述

什么是Spring的依赖注入(DI)

实现控制反转的是IOC容器,实现方式是依赖注入
IOC容器根据目标对象的依赖关系,自动注入依赖的对象
在这里插入图片描述

在这里插入图片描述

依赖的注入方式(构造器注入+set方式注入)–(Bean的xml显示配置)

在这里插入图片描述
构造器注入
在这里插入图片描述

set方法注入(需要手动加入成员变量的属性)
在这里插入图片描述
在这里插入图片描述

    <bean id="address" class="com.kuang.pojo.Address">
        <property name="address" value="南京"/>
    </bean>

    <bean id="student" class="com.kuang.pojo.Student">
<!--        1.普通方式注入-->
        <property name="name" value="qinjiang"/>
<!--        2.bean注入-->
        <property name="address" ref="address"/>
<!--        3.数组注入-->
        <property name="books">
            <array>
                <value>全球高考</value>
                <value>好生开车</value>
                <value>某某</value>
            </array>
        </property>
<!--        4.list注入-->
        <property name="hobbies">
          <list>
              <value>听歌</value>
              <value>游戏</value>
              <value>敲代码</value>
          </list>
        </property>
<!--        5.map注入-->
        <property name="card">
            <map>
                <entry key="身份证" value="112345"/>
                <entry key="电话号码" value="1525"/>
            </map>
        </property>
<!--        6.set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
            </set>
        </property>
<!--null-->
        <property name="wife">
            <null/>
        </property>
<!--        7.properties注入-->
        <property name="info">
            <props>
                <prop key="学号">2019</prop>
                <prop key="性别">男性</prop>
            </props>
        </property>

    </bean>

在这里插入图片描述

什么是Spring bean

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .
在这里插入图片描述

Bean的作用域

在这里插入图片描述

解决Bean的线程安全问题:1.不要在class对象中创建可变的成员变量;2.将Bean设置为prototype类型;3.实在要使用可变的成员变量,使用ThreadLocal,本地线程的局部变量(注意防止内存泄漏)
在这里插入图片描述

在这里插入图片描述

单例 bean 的线程安全问题了解吗?

在这里插入图片描述

在这里插入图片描述

Spring如何处理并发线程安全问题

在这里插入图片描述

Bean的生命周期(太难了,放弃)

1. Bean实例化阶段(扫描Component+定义bean):就是获取扫描的component的class对象封装进Beandefinition(Class,scope类型单例or原型),装进beandefinition的hashmap容器中(键为beanname,值为Beandedinition)----如果是单例的class需要先创建实例对象放入hashmap容器缓存

2. Bean初始化:docreate()阶段,主要是从beandedinition拿到class的实例对象,设置好reference类型的属性(主要是扫描Autowired注解的field字段设置属性)–》该类实现了BeanNameAware接口的执行相应的aware回调–》BeanPostProcessor的初始化前后置处理(一般初始化后置postProcessAfterInitialization用于实现AOP)+中间夹杂着是否类实现了InitializingBean接口执行相应的afterPropertiesSet()

在这里插入图片描述

在这里插入图片描述

spring容器上下文环境的自定义实现

public class ZhouyuApplicationContext {

    private Class configClass;//配置类
//    放置单例bean的池子singletonObjects(beanName,class对象)
//    bean定义的池子beanDefinitionMap((beanName,bean的定义--主要是bean的类型---单例、原型))
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
//    bean的后置处理器的列表
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();


    
//    配置好spring容器并做好扫描工作,完成所有的扫描(相当于定义+ 注册好需要的bean)
    public ZhouyuApplicationContext(Class configClass){

        this.configClass=configClass;

//        解析配置类:@ComponentScan扫描类路径
        scope(configClass);

        // 定义bean+加载“单例”bean(注意必须是单例bean的情况下)
        instanceSingletonBean();

    }


    //        解析配置类:@ComponentScan扫描类路径
    private void scope(Class configClass) {
        ComponentScan componentScanAnnotations =(ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        String path = componentScanAnnotations.value();
        System.out.println(path);
        path = path.replace(".", "/");
        ClassLoader classLoader = ZhouyuApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        if(file.isDirectory()){
            File[] files = file.listFiles();
            for(File file1:files){
                System.out.println("【文件scope阶段】"+file1);
                String absolutePath = file1.getAbsolutePath();
//                判断是不是class文件类型
                if (absolutePath.endsWith(".class")) {
                    String substring = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));

                    // 获取类的全限定名
                    String className = substring.replace("\\", ".");//com.zhouyu.service.UserService
                    System.out.println("【文件scope阶段】"+className);

                    try {
//                        加载类+放入bean定义的池子中--前提是先定义好bean的类型信息(原型、单例)
                        Class<?> clazz = classLoader.loadClass(className);
//                        首先判断这个类是否是component组件
                        if(clazz.isAnnotationPresent(Component.class)){

                            //判断这个bean是不是bean的后置处理器
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                try {
                                    BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                                    beanPostProcessorList.add(instance);
                                } catch (InstantiationException e) {
                                    e.printStackTrace();
                                } catch (IllegalAccessException e) {
                                    e.printStackTrace();
                                } catch (InvocationTargetException e) {
                                    e.printStackTrace();
                                } catch (NoSuchMethodException e) {
                                    e.printStackTrace();
                                }
                            }

//                            ....解析bean,判断是否是单例 的bean
                            Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
                            String beanName = componentAnnotation.value();

                            BeanDefinition beanDefinition = new BeanDefinition();//bean的定义对象、
                            beanDefinition.setBeanClass(clazz);
//                            单例bean还是原型的bean
                            if(clazz.isAnnotationPresent(Scope.class)){
                                Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
                                beanDefinition.setScope(scopeAnnotation.value());
                            }else{
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);
                        };

                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }

                }
            }
        }
    }


    
//    创建单例bean的实例,放入缓存中
    private void instanceSingletonBean() {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = doCreateBean(beanName, beanDefinition);
//                放入单例bean的hasnmap的赤字中
                singletonObjects.put(beanName, bean);
            }
        }
    }

    
//创建bean对象的方法+注入依赖的对象(Autowired依赖注入)+bean的后置处理器的初始化前和初始化之后的处理
    private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
//        当前要创建的bean的类型
        Class beanClass = beanDefinition.getBeanClass();
        try {
            Object instance = beanClass.getDeclaredConstructor().newInstance();

            // 填充属性+实现依赖注入(所有字段的类型+是否标注Autowired注解)


     // 将标注Autowired注解字段值放入原生的构造器的字段中中,实现属性的填充(造成依赖注入更早的创建bean对象)
            Field[] fields = beanClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    String fieldName = field.getName();
                    Object bean = getBean(fieldName);
//                    该字段可以被获取
                    field.setAccessible(true);
                    //将字段值放入原生的构造器中,实现属性的填充,完成真正的初始化工作
                    field.set(instance, bean);
                }

            }

            // Aware回调:实现基本数据类型的包装类型的属性注入
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }

            // 初始化之前,BeanPostProcessor(由于每个bean都需要经过这个方法,所以后置处理器是第一个创建bean对象的)
            for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
                beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
            }

            // 初始化
            if (instance instanceof InitializingBean) {
                ((InitializingBean)instance).afterPropertiesSet();
            }

            // 初始化之后,BeanPostProcessor
            for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
//                (返回被代理的对象)
                instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
            }


            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }


        return null;
    }


//从容器中获取bean,可能是从缓存---hashmap,也可能直接创建新的class对象
    public Object getBean(String beanName){
        if(beanDefinitionMap.containsKey(beanName)){
            if (singletonObjects.containsKey(beanName)) {
                return singletonObjects.get(beanName);
            } else {
//                如果是原型的bean对象,此时当场进行bean的创建
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                return doCreateBean(beanName, beanDefinition);
            }
        }else{
            throw new NullPointerException();
        }
    }


}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

afterPropertiesSet的使用

深入理解SpringBean生命周期之InitializingBean详解

在这里插入图片描述

Bean的自动装配原理(隐式配置)

在这里插入图片描述

首先需要扫描到所有的组件,在初始化bean的设置属性自动装配Autowired

在这里插入图片描述

xml显示配置方式
autowired 属性Byname的自动配置(class对象要有setFiled的方法)

这些属性的对象肯定提前放到容器的beanDefinition中了
在这里插入图片描述
在这里插入图片描述

autowired 属性Bytype的自动配置

在这里插入图片描述
在这里插入图片描述

使用注解实现自动装配(@Autowired/@Resource/@Qualifier)

需要在配置文件中开启注解的支持
在这里插入图片描述

@Autowired注解

在这里插入图片描述

是依赖对象不存在
在这里插入图片描述

@Qualifier注解(不能单独使用,需要Autowired注解搭配)

在这里插入图片描述

@Resource注解(3级原则–>byname+bytype+抛异常)

在这里插入图片描述

具体的装配过程

在这里插入图片描述

Spring注解(java中的bean显示配置)

声明为Bean的注解有哪些?

@component,@Controller,@Service,@Mapper,@Repository,@Configuration(结合@Bean)----这些都需要通过类路径来扫描
在这里插入图片描述

@Bean(方法返回对象注册)和@Component(类注册)注解的区别

在这里插入图片描述
在这里插入图片描述

@Configuration注解(一般@Bean需要它的搭配)

在这里插入图片描述

Spring AOP(面向切面编程)–底层:代理模式

在这里插入图片描述
注意:实际JDK动态代理的invoke()方法和CGLIB的interceptor()方法实际调用的都是AOP的AdvisedSupprt类的MethodInterceptor的invoke()方法
在这里插入图片描述

静态代理和动态代理的区别

什么是编译期和运行期

编译期就是生成class字节码文件的过程
运行期就是解释执行字节码文件的过程
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

动态代理模式(JDK动态代理和CGLIB动态代理)

动态代理模式javaguide

在这里插入图片描述

JDK动态代理的核心:Proxy类和InvocationHandler接口(只能代理实现了接口的类)

Proxy类:
在这里插入图片描述

InvocationHandler接口:

在这里插入图片描述

在这里插入图片描述

Proxy类提供了创建动态理类的实例的方法newProxyInstance,且每个动态代理类有一个==“相关联”==的“调用处理程序对象”—即实现了InvocationHandler接口的类,InvocationHandler接口的invoke方法即可以获取代理类的目标对象的所有方法+可以自定义添加方法。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

CGLIB代理的核心MethodInterceptor 接口和 Enhancer 类是核心(代理任何类)

在这里插入图片描述
在这里插入图片描述

总结与对比

在这里插入图片描述

Spring AOP 和 AspectJ AOP 有什么区别?

在这里插入图片描述
在这里插入图片描述

解释一下Spring AOP里的几个名词

狂神的具体实现应用
在这里插入图片描述

在这里插入图片描述

Spring MVC

什么是MVC

在这里插入图片描述

什么是Spring MVC

在这里插入图片描述

Spring MVC的工作原理

在这里插入图片描述

dispatchservlet表示servlet的转发器:
在这里插入图片描述

简单的应用实现理解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Restful风格详解

在这里插入图片描述

路径变量的优势(对比请求参数@RequestParam)

在这里插入图片描述

在这里插入图片描述

传统中请求参数的拼接,使用?name=val

深入理解@RequestBody

Spring事务管理

事务是逻辑上的一组操作,要么都执行,要么都不执行

事务的ACID特性

在这里插入图片描述

spring事务管理的两种方式

在这里插入图片描述
在这里插入图片描述

事务的传播特性(针对声明式事务的@Transaction注解,默认:PROPAGATION_REQUIRED)

在这里插入图片描述
某事务“挂起”之后,任何操作都不在该事务的控制之下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Spring事务的隔离级别

在这里插入图片描述

@Transaction接口(声明式事务)

作用范围

在这里插入图片描述

注解的常用配置参数

在这里插入图片描述

@Transaction注解原理(AOP)

在这里插入图片描述
可能同一类中的方法自调用被transaction标注的方法,spring容器启动的时候压根没有扫描到该方法的注解,更不会为其创建代理对象!!!(我觉得是这样)

Spring AOP的自调用问题

在这里插入图片描述

@Transaction注解失效的场景

在这里插入图片描述

Spring中用到的设计模式(不为难自己了)

在这里插入图片描述

工厂模式( BeanFactory 或 ApplicationContext)

Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。

什么是工厂模式

在这里插入图片描述

BeanFactory 或 ApplicationContext的区别

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

单例模式(Bean的默认作用域)

什么是单例模式(做好手撕的准备)**

单例模式详解
在这里插入图片描述
在这里插入图片描述

bean的作用域

在这里插入图片描述

代理模式(Spring AOP)

在这里插入图片描述

在这里插入图片描述

模板模式(***Template的类)

不就是我们SpringMVC中service(接口约束行为)和serviceImpl(接口的实现类)的模式,但是这样还有一个原因是为了JDK动态代理方便!!!
在这里插入图片描述

在这里插入图片描述

观察者模式(ApplicationListener)----许多的监听器&回调机制

在这里插入图片描述

在这里插入图片描述
== Spring事件驱动模型中的三种重要角色:事件,事件监听者,事件发布者(为啥像“生产者与消费者模式”???不明白–是有无消息队列的区别吗)好像是消息队列的区别==
在这里插入图片描述

到此为止!!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值