搭配视频地址https://www.bilibili.com/video/BV1vS4y1h7Kn?p=1
一、Spring Framework
1. 谈谈你对Spring的理解
什么是spring
- Spring是一个生态:可以构建java应用所需的一切基础设施
- 通常Spring指的就是Spring Framework
核心解释
spring是一个轻量级的开源容器框架。
spring是为了解决企业级应用开发的业务逻辑层和其他各层对象直接的耦合问题
spring是一个IOC和AOP的容器框架。
- IOC:控制反转
- AOP:面向切面编程
- 容器:包含并管理应用对象的生命周期
2. Spring的优缺点是什么?
特点:
-
方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦
合。
有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
人话:集中管理对象,对象和对象之间的耦合度减低,方便维护对象。
-
AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应
付。
Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式管理,从而提供了更好的复用.
人话: 在不修改代码的情况下可以对业务代码进行增强 减少重复代码, 提高开发效率,维护方便
-
声明事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效
率和质量。
人话:提高开发效率,只需要一个简单注解@Transactional
-
方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,而是随手可做的事
情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
图灵课堂
人话:Spring实现测试 使我们 可以结合junit非常方便测试Spring Bean SpringMVC
-
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架
(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
人话:拥有非常强大粘合度、集成能力非常,只需要简单配置就可以集成第三方框架
-
降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易
封装,这些Java EE API的使用难度大为降低。
人话:简化开发, 帮我封装很多功能性代码
-
Java 源码是经典学习范例
Spring的源码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造
诣。Spring框架源码无疑是Java技术的最佳实践范例。如果想在短时间内迅速提高自己的Java技术水平和应用开发水
平,学习和研究Spring源码将会使你收到意想不到的效果。
人话:学习到了Spring底层的实现,反射..设计模式 都是我们值得学习, 提供非常多的扩展接口供外部进行扩展
缺点
- 从应用层面来说是没有缺点的
- 简化开发, 如果想深入到底层去了解就非常困难(上层使用越简单、底层封装得就越复杂)
源码缺点:由于spring 大而全(要集成这么多框架、提供非常非常多的扩展点,经过十多年的代码迭代) 代码量非常庞大 ,一百多万 对于去深入学习源码带来了一定困难。
二、Spring IOC
3. 什么是Spring IOC 容器?有什么作用?
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对
象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周
期。
对于 IOC 来说,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。
控制反转(IOC )有什么作用
- 管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系
需要程序猿来维护的话,那是相当头疼的 - 解耦,由容器去维护具体的对象
- 托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序
可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的
IOC的优点是什么?
最小的代价和最小的侵入性使松散耦合得以实现。
人话:
作用:
控制反转 控制了什么?
UserService service=new UserService(); // 耦合度太高 、维护不方便
引入IOC就将创建对象的控制权交给Spring的IOC . 以前由程序员自己控制对象创建, 现在交给Spring的IOC 去创建,
如果要去使用对象需要通过DI(依赖注入)@Autowired 自动注入 就可以使用对象 ;
优点:
- 集中管理对象、方便维护 。
- 降低耦合度
- IOC容器支持加载服务时的饿汉式初始化和懒加载
4. Spring IoC 的实现机制是什么?
Spring 中的 IOC的实现原理就是工厂模式加反射机制。
public class IocDemo {
public static void main(String[] args) {
//耦合度过高
//UserServiceImpl userService=new UserServiceImpl();
//介于上面出现的耦合度过高的原因,因此采用简单工厂模式
BaseService userService=Factory.getBean("user");
//简单工厂+完整类路径反射模式
BaseService roleService=Factory.getBean("package com.yc.tuling");
}
}
//简单工厂:一种设计模式,通过一个方法传入一个标识,生产对应对象(举例的代码是懒加载的情况,Spring容器启动的时候就通过将所有的非懒加载的类的完整类路径,利用反射生成实例对象)
class Factory{
//如果增加bean,或者修改bean,对其修改的代码太多
// public static <BaseService> BaseService getBean(String beanName){
// BaseService baseService=null;
// if ("user".equals(beanName)){
// baseService= (BaseService) new UserServiceImpl();
// }
// if ("role".equals(beanName)){
// baseService= (BaseService) new RoleServiceImpl();
// }
// return baseService;
// }
public static BaseService getBean(String className){
BaseService baseService=null;
try {
//通过反射 根据需要创建对象的完整类路径
baseService= (BaseService) Class.forName(className).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return baseService;
}
}
5. IOC和DI的区别
IOC是用来解决耦合的一种思想,而DI是IOC的重要一环的实现。
6. 紧耦合和松耦合有什么区别?
紧耦合:
紧密耦合是指类之间高度依赖。
松耦合:
松耦合是通过促进单一职责和关注点分离、依赖倒置的设计原则来实现的。
7. BeanFactory的作用
- BeanFactory是Spring中非常核心的一个顶层接口(无父接口);
- 它是Bean的“工厂”、它的主要职责就是生产Bean;
- 它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean(笔记:凡是以Factory结尾的,基本都实现了简单工厂的设计模式);·
- 它有非常多的实现类、每个工厂都有不同的职责(单一职责)功能,最强大的工厂是:DefaultListableBeanFactory(它继承和实现了很多接口或者类,根据父子类的特点,因此DefaultListableBeanFactory相当强大)
- Spring底层就是使用的该工厂进行生产Bean的(Spring使用的ApplicationContext底层就是间接实现了BeanFactory,在new ApplicationContext对象的时候,就直接new了DefaultListableBeanFactory)
- BeanFactory它是Spring容器(管理着Bean的生命周期)
8. BeanDefinition的作用
它主要负责存储Bean的定义信息:决定Bean的生产方式
换句话说:BeanDefinition的属性就是对应Bean的定义信息,而BeanFactory根据这些信息生产Bean。
如:spring.xml
<bean class="com.tuling.User" id="user" scope="singleton"
lazy="false" abstract="false" autowire="none" ....>
<property name="username" value="xushu">
</bean>
后续BeanFactory根据这些信息生产Bean: 比如实例化,可以通过class进行反射进而得到实例对象,比如lazy则不会在IOC 加载时创建Bean
9. BeanFactory和ApplicationContext有什么区别
关系: ApplicationContext实现了BeanFactory。
共同点: 都可以作为容器。
区别:
- BeanFactory用于生产bean(getBean()方法)。
- ApplicationContext实现了BeanFactory,ApplicationContext不生产bean,而是通知 (用的DefaultListableBeanFactory)来进行生产
- ApplicationContext的getBean是一个门面方法,做的事情比较多
- 会自动帮我们把配置的bean注册进来
- 加载环境变量
- 支持多语言
- 实现时间监听
- 注册很多扩展节点
10. BeanFactory 和FactoryBean有什么区别?
BeanFactory是一个工厂,也就是一个容器,是来管理和生产bean的。
FactoryBean
- 是一个bean,但是它是一个特殊的bean,所以也是由BeanFactory来管理的
- 它是一个接口,它必须被一个类去实现。不过FactoryBean不是一个普通的Bean,它会表现出工厂模式的样子,是一个能产生对象的工厂Bean,里面的getObject()就是用来获取FactoryBean产生的对象。所以在BeanFactory中使用“&”来得到FactoryBean本身,“&”用来区分通过容器获取FactoryBean产生的对象还是获取FactoryBean本身。
代码解释
配置类
@Configuration
@ComponentScan
public class MainConfig {
}
实现FactoryBean接口的类
@Component
public class UserMapper implements FactoryBean {
public UserMapper() {
System.out.println("UserMapper加载...");
}
public void query(){
System.out.println("query");
}
@Override
public Object getObject() throws Exception {
return new RoleMapper()111;
}
@Override
public Class<?> getObjectType() {
return RoleMapper.class;
}
}
测试启动类
public class Run {
public static void main(String[] args) {
AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(MainConfig.class);
//通过& 可以得到原实例即userMapper,不加&默认返回的是getObject()方法返回的对象即RoleMapper
UserMapper userMapper= (UserMapper) context.getBean("&userMapper");
userMapper.query();
}
}
注意:
- UserMapper类的实例对象一定会加载即饿汉加载,不管getBean()的时候加不加“&”
- 但是如果不加“&”,getBean()取到的对象就不是UserMapper类的实例对象,而是getObject()方法返回的对象
- 但是getObject()方法返回的对象的加载是懒汉加载,即getBean()且不加“&”的情况下,才会加载并且取出实例对象返回