| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Spring知识点整理 -> 正文阅读 |
|
[Java知识库]Spring知识点整理 |
目录 1、Spring是如何创建一个Bean对象的Service类---->推断构造方法---->普通对象(没有属性值)---->依赖注入(给加了@Autowired注解的属性赋值)---->初始化前(调用对象内从数据库抓取属性并封装为对象返回的方法,该方法上有@PostConstruct)---->初始化(InitialIzingBean接口)---->初始化后(AOP)---->代理对象---->代理对象放入Map单例池(多例Bean情况下省略)----->Bean对象(有属性值) 利用Service类通过无参的构造方法得到一个对象,判断有哪些属性,各属性上面是不是存在@Autowired注解,如果存在注解,就利用反射给当前Service类的对象中的属性赋值。 2、什么是单例池?作用是什么?单例Bean指向的对象是同一个。 实现这一点是由于底层为Map结构。以beanName为key,Bean对象为value。这个Map就被称为单例池。该Map存放的是单例Bean对象。 如果创建的是多例Bean,那么在创建Bean对象的过程中就不需要放入单例池。 3、Bean对象和普通对象之间的区别是什么?大部分是一样的,只是不同过程中的称呼不同。 普通对象经过依赖注入等过程后,属性得到赋值,成为Bean对象。 4、依赖注入是怎么实现的?对无参构造的对象进行判断,看哪些属性上面存在@Autowired注解,如果存在注解,就利用反射给当前Service类的对象中的属性赋值。 5、@PostConstruct注解是如何工作的?依赖注入后,获得对象的每个方法,判断方法上是否有@PostConstruct注解,如果有该注解,就执行正在创建的Bean对象中的该方法。 Spring的Bean在创建时进行初始化,初始化的过程中会解析出@PostConstruct注解的方法,并反射调用该方法。从而在启动时执行该方法。 6、Bean的初始化是如何工作的?判断对象是否实现了InitializingBean方法,如果实现了就打印一个日志。而后判断安全管理器getSecurityManager是否打开(默认是不打开,为false)。而后把该对象bean进行强转,转为InitializingBean类,调用afterPropertiesSet方法(该方法没有参数,仅作为通知)。 详细流程如下: ①通过实现BeanFactoryPostProcessor并覆盖postProcessBeanFactory()可以在spring容器初始化时拿到ConfigurableListableBeanFactory的实例,ConfigurableListableBeanFactory是所有bean的容器,也是BeanFactory的基础实现。此处可以对ConfigurableListableBeanFactory做扩展。 ②执行当前bean的构造函数 ③实现了BeanNameAware的接口会执行setBeanName()可以拿到bean的id ④实现了BeanFactoryAware的接口会执行setBeanFactory()可以拿到beanFactory实例 ⑤执行init-method即@PostConstruct ⑥实现了InitializingBean的接口的会执行afterPropertiesSet(),该方法没有参数,仅仅是作为通知 ⑦继承了InstantiationAwareBeanPostProcessorAdapter并重写了其中的postProcessBeforeInstantiation方法则会拿到bean的Class类型实例和beanName ⑧继承了InstantiationAwareBeanPostProcessorAdapter并重写了其中的postProcessAfterInstantiation方法则会拿到bean的实例和beanName ⑨继承了InstantiationAwareBeanPostProcessorAdapter并重写了其中的postProcessPropertyValues方法则会拿到bean的实例、bean的名称、属性值、属性描述符 ⑩继承了InstantiationAwareBeanPostProcessorAdapter并重写了其中的postProcessAfterInitialization方法则会拿到bean的实例和beanName ?执行destroy前的回调 ?destroy之后的回调 7、Bean的初始化和实例化区别是什么?Bean的初始化是调用InitializingBean接口中的方法,也可以理解为执行Bean实例出的对象中的某个方法(?) Bean的实例化就是通过无参的构造方法构造对象的过程。 8、推断构造方法是什么意思?当Spring发现一个类里有多个构造方法,且没有指定用哪一个构造方法时,会扫描这几个构造方法中是否含有无参构造器,然后使用该构造方法;如果只有一个构造方法,就直接使用。 推断构造方法即推断你要使用哪一种构造方法。 也可以通过@AutoWired注解告诉Spring要用哪一个构造方法。 9、单例Bean和单例模式之间有什么关系?Spring单例Bean与单例模式的区别在于它们关联的环境不一样,单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。在一个JVM进程中,如果有多个Spring容器,即使是单例Bean,也一定会创建多个实例。 (简单理解,对于一个JVM进程,可能有多个Spring容器,就算每个容器都是单例Bean,但是对于整个JVM进程来讲,也不是单例模式。) 10、什么是先byType再byName?byName就是通过Bean的属性名称(或者id或name)自动装配。 byType就是通过Bean的class类型来自动装配。在使用autowired by Type需要保证:同一类型的对象,在Spring容器中唯一。 这里引入@AutoWired和@Resource区别: 1. @AutoWired和@Resource都可以来装配Bean,都可以写在字段上,或者setter方法上; 2. 作用方式相同,但是执行顺序不同。@AutoWired先byType,默认情况下依赖对象必须存在,如果要允许null值,需设置required = false,如果想使用byName装配要结合@Qualified注解。@Resource默认先byName,当找不到与名称匹配的bean时才按照类型进行装配。但是如果name属性指定,就只按照名称装配。 11、Spring AOP底层是怎么工作的?使用动态代理 动态代理有两种情况: (1)第一种 有接口情况,使用JDK动态代理。即创建接口实现类代理对象,增强类的方法。 (2)第二种 没有接口的情况,使用CGLIB动态代理。创建子类的代理对象,增强类的方法。 一般使用第一种,因为接口可以实现多个类,而子类只能继承单个类。 首先创建Dao接口,定义要增强的方法,然后创建接口实现类,实现方法,最后使用Proxy类创建接口代理对象。利用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法,其中ClassLoader loader是类加载器(一般是写这方法时所在的类的加载器,即xxx.class.getClassLoader),Class<?>[] interfaces是增强方法所在的类实现的接口集合(即Dao接口的类),InvocationHandler h是实现InvocationHandler接口,创建代理对象,写增强的部分。 12、Spring事务底层是怎么工作的?首先要了解的是,事务是SQL语句的集合,有四个特性(ACID):原子性、一致性、隔离性、持久性。 事务有4个隔离等级:1、READ_UNCOMMITTED读未提交,未解决任何并发问题 2、READ_COMMITTED读已提交,解决数据脏读,存在不可重复读和幻读 3、REPEATABLE_READ可重复读,解决数据脏读、不可重复读,存在幻读(MySQL的默认隔离级别) 4、ZERIALIZABLE:串行化,不存在并发问题。 有两种事务实现方式:编程式事务、声明式事务 编程式事务:在代码中进行事务控制。优点是精度高,缺点是代码耦合度高 声明式事务:通过@Transactional注解实现事务控制,用的比较多,使用后事务的自动功能会关闭,由Spring实现事务的控制。 Spring的事务管理是通过AOP代理实现的,对被代理的对象中的每个方法进行拦截,在方法执行前启动事务,在方法执行完成后根据是否有异常以及异常的类型进行提交或者回滚(rollback)。 原理:当在某个类或者方法上使用@Transactional注解后,spring会基于该类生成一个代理对象,并将这个代理对象作为bean。当调用这个代理对象的方法时,如果有事务处理,则会先关闭事务的自动功能,然后执行方法的具体业务逻辑,如果业务逻辑没有异常,那么代理逻辑就会直接提交,如果出现任何异常,那么直接进行回滚操作。当然我们也可以控制对哪些异常进行回滚操作。 13、同类方法调用为什么会事务失效?因为它们发生了自身调用,就调该类自己的方法,而没有经过Spring的代理类,默认只有在外部调用事务才会生效,这也是老生常谈的经典问题了。在同一个class中,方法B调用方法A,调用的是原对象的方法,而不通过代理对象。 14、@Configuration注解的作用是什么?声明一个类为配置类,用于取代bean.xml配置文件注册bean对象。默认情况下以饿汗单例的形式进行创建,即IOC容器创建时就创建bean对象。 例: 15、Spring为什么要用三级缓存来解决循环依赖?1.什么是循环依赖?循环依赖即两个或多个Bean对象互相之间的持有对方的引用。 2.哪些情况会出现循环依赖?(1)相互依赖(2)三者间依赖(3)自我依赖 3.三级缓存如何解决循环依赖?一级缓存:单例对象集合 singletonObjects(ConcurrentHashMap) 二级缓存:早期单例对象集合,即创建的单例对象未完全初始化earlySingletonObjects(ConcurrentHashMap) 三级缓存:单例对象工程集合,存储的是对象封装后的ObjectFactory singletonFactories(HashMap) 流程如下: 以orderService(os)和userService(us)这个例子来说明 1. get os的bean,调用getSingleton(String) 但是为null; 2. 将os放入表示正在创建的集合中; 3. 实例化os的对象; 4. 调用addSingletonFactory(String, ObjectFactory) 将os所对应的 ObjectFactory放入三级缓存; 5. os对象进行属性填充; 6. os属性填充时发现属性是us,调用 getSingleton(String) 获取us的bean,但是为null; 7. 将us放入表示正在创建的集合中; 8. 实例化us的对象; 9. 调用addSingletonFactory(String, ObjectFactory) 将us所对应的 ObjectFactory放入三级缓存; 10. us进行属性填充; 11. us进行属性填充时,发现属性是os,就调用 getSingleton(String) 获取us的bean,这是能够获取到,us属性填充完毕; 12. us初始化完成,方法栈返回,os属性填充完毕,os初始化完成。 题外:AOP和IOC的概念解析1.AOP:面向切面编程,是一种可配置的、可插拔的程序结构。从Spring的角度来说,AOP最大的用途在于提供了事务管理的能力,即只关注想关注的事,其余的事都交给别人去干。在AOP中即事务管理是关注点,而访问数据库是想做的且必须要做的事,那么Spring就会在访问数据库之前自动开启事务,在访问数据库结束之后自动提交或回滚事物。 2.IOC:控制反转,也可称为依赖倒置。首先先了解依赖的概念,从程序的角度看即A要调用B的方法,就必须主动获取B的实例,才可以调用b对象。而依赖倒置的意思就是不需要主动获取B的实例,而是由Spring将B的实例自动实现。Spring实现依赖注入的方式是动态代理。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 13:02:01- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |