1.什么是框架
框架: 高度抽取可重用代码的一种设计
2.什么是spring?
Spring是一个轻量级Java开发框架,目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。
底层都依赖于它的两个核心特性,也就是依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP)
3.IOC(inversion of control)控制反转
控制:资源的获取方式
主动式:需要的资源自己创建
被动式:资源交给容器来创建和设置
4.容器:
管理所有的资源(类);容器可以自动探查那些组件(类)需要用到另一些组件(类),上图中,容器自动创建BookService对象,并把BookService对象赋值过去
5.DI(依赖注入) dependency injection:
容器通过反射的方式,将容器中准备好的BookService对象注入到BookServlet中
6.Spring IoC 的实现机制
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
if(f!=null){
f.eat();
}
}
}
7.Spring 的 IoC支持哪些功能
Spring 的 IoC 设计支持以下功能:
依赖注入
依赖检查
自动装配
支持集合
8.框架编写流程:
1.导包:四个核心容器+日志包
2.写配置:创建Spring Bean Configuration File(配置文件),xml格式
9.Spring有几种配置方式
这里有三种重要的方法给Spring 容器提供配置元数据。
XML配置文件。
基于注解的配置。
基于java的配置。
10.通过xml配置方法
在Bean配置文件中注册一个组件(对象/类),Spring会自动创建这个对象/类
class: 要注册组件的全类名
id属性: 这个对象的唯一标识
property属性: 为这个对象赋值,name属性名,value属性值
ioc.xml
ApplicationContext代表ioc容器
ApplicationContext ioc = new ClassPathXmlApplicationContext(“ioc.xml”)根据spring配置文件得到ioc对象
ClassPath表示当前的配置文件在类路径下
ioc.getBean+id返回一个Person对象(通过容器创建对象)
Test.java
11.对象是什么时候创建好的?
容器中对象的创建在容器创建完成的时候就已经完成了,不是ioc.getBean()时创建
12.Spring基于xml注入bean的几种方式
Set方法注入;
构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
静态工厂注入;
实例工厂;
12.setter方法是怎样赋值的
ioc容器在创建这个组件/对象的时候,property会利用setter方法为JavaBean的属性进行赋值
JavaBean的属性名name是由什么决定的?getter/setter方法决定的,set去掉后面那一串首字母小写
故属性名为lastname
13.调用有参构造器进行对象创建并赋值
有多少个构造器参数就写多少个constructor-arg,name属性可以省略
14.使用ref引用外部bean
Car和Person是不同java文件中的两个类,通过ref引用外面的一个值,也就是car01组件,通过Person类型对象bean能够调用Car类型中的方法
返回true,这两个car是同一个对象
15.引用内部bean
16.abstract和parent
通过abstract来创建一个模板bean
该bean只能被继承,使其配置文件被继承,不能被获取,getBean(person05)会报错
parent用来继承其他bean的配置信息,property中只需写上要改的部分,bean的继承和类的继承不是一回事
17.bean之间的依赖 depends-on
以前是按照注册组件的顺序创建对象,depends-on之后:
18.Spring支持的几种bean的作用域
singleton(默认) : bean在每个Spring ioc 容器中只有一个实例。
prototype:一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
19.Spring框架中的单例bean是线程安全的吗?
不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
要实现线程安全,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
20.工厂模式:
有一个专门创建对象的类,这个类成为工厂
静态工厂: 工厂本身不用创建对象,通过静态方法调用:对象=对象工厂类.方法名()
静态方法随着类的加载而加载,不需要创建实例,调用直接用类名.方法名()
实例工厂: 工厂本身需要创建对象,工厂对象 = new 工厂类(),通过调用工厂对象的方法返回一个对象
如果不指定factory-method,会默认创建AirPlaneStaticFactory类型的对象,指定后获取一个AirPlane类型的对象,通过constructor-arg对getAirPlane方法传参
调用ioc.getBean(id)返回的是AirPlane类型的对象,而不是工厂类类型的对象
先配置实例工厂对象,然后在配置要创建的对象,指定用哪个工厂创建,以及创建对象的工厂方法
21.BeanFactory 和 ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
22.ApplicationContext通常的实现是什么?
FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
23.bean 的生命周期
24.基于xml的自动装配/spring 自动装配 bean 有哪些方式?
1.通过属性名byName
2.通过类型byType
3.通过构造器constructor
autowire byName 通过属性名作为id去容器中查找相应的组件,找不到装配null
在bean中并没有对person的car属性赋值,通过autowire自动装配
注意是以属性名作为id,如果容器中Car组件的id不是car,那么就赋值不上,null
autowire byType时,通过类型查找组件实现自动装配,如果容器中注册了两个Car类型的组件,那么就会报错
用有参构造器进行装配:两步走,先按照类型去容器中查找组件,有多个再用属性名作为id查找
25.@Component, @Controller, @Repository, @Service
通过注解,快速将bean加入到ioc容器中
26.自动扫描加了注解的组件
使用context名称空间扫描需要扫描的包,扫描完成后,ioc容器就接管了这几个加了注解的类
27.@Scope注解
将单例模式改为多例模式
28.@Autowire注解实现属性的自动装配
29.@Autowire注解自动装配过程
1.先按照类型去容器中查找对应组件
2.如果有一个,装配,如果有多个,再将变量名作为id去容器中查找
容器中,BookServiceExt类型的默认id时bookServiceExt,BookService默认id是bookService,再比较变量名,调用变量名和id相同的类
bookServiceExt2变量名作为id不能匹配到相应的类,报错
30.@Qualifier注解
指定一个变量名作为id,去容器中查找
31.@Required注解
如果autowire自动装配,在容器中没有找到对应的组件,会报错,设置required == false,则装配null
32.@Autowired和@Resource之间的区别
@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
33.面向切面编程(AOP):
将某段代码动态地切入到指定方法的指定位置进行运行的一种编程方式
34.jdk动态代理
日志记录和业务逻辑代码发生耦合
动态代理:日志记录功能更强大,与业务逻辑解耦
先写接口
再写实现类
创建一个CalculatorProxy类
InvocationHandler是目标方法执行器,使用动态代理执行
写入日志:
jdk默认的动态代理,如果目标对象没有实现任何接口,是无法为他创建代理对象的
34.代理对象和被代理对象关系
代理对象和Calculator不是同一个类,代理对象和被代理对象的唯一关联是实现了同一个接口
35、JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
36、连接点、切入点、切入点表达式、切面类、横切关注点、通知方法
37、Spring通知有哪些类型?
前置通知(@Before):在目标方法被调用之前调用通知功能;
后置通知(@After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
返回通知(@After-returning ):在目标方法成功执行之后调用通知;
异常通知(@After-throwing):在目标方法抛出异常后调用通知;
环绕通知(@Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
38、execution切入点表达式
权限修饰符+返回值类型+方法签名
方法签名为全类名+方法名(如果是所有方法用*)+参数列表
39、AOP基本步骤:
导包、写配置、测试
写配置:
1.将目标类和切面类注册到ioc容器中,MyMathCalculator用@Service注解,LogUtil用@Component注解
2.告诉spring哪个是切面类**@Aspect**
3.告诉spring,切面类里面的方法何时执行
4.开启基于注解的AOP功能
40、Spring支持的事务管理类型, spring 事务实现方式有哪些?
Spring支持两种类型的事务管理:
编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
41、事务切面
即事务管理器(DataSourceTransactionManager),在目标方法运行的前后进行事务控制
42、@Transactional(timeout = int)
设置超时秒数,事务超出指定时长后自动终止并回滚
43、@Transactional(readOnly = Boolean)
对事务进行优化,readOnly = true加快查询速度
44、事务的回滚
默认运行时异常(非检查异常)回滚,编译时异常(检查异常)不回滚
数学错误1/0属于运行时异常,默认回滚,添加noRollbackFor使它不回滚,RollbackFor使编译时异常回滚
45、Spring的事务传播行为
事务出现嵌套,子事务是否要和大事务共用一个事务
比喻:两家一起旅游,老王开车,另一家要不要开新车
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。(开一辆车,出异常全部回滚)
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。(开两辆车,出异常的事务回滚)
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
如果两个事务都是REQUIRES_NEW