Spring是一个轻量级(核心jar包比较小,但是数量多),非侵入式(框架代码不会侵入业务代码,业务代码也不会实现或继承框架中接口或类)的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业级应用程序的开发,它使得开发者只需关心业务需求。
IoC就是,控制反转,就是将原本自己手动new Bean
对象的能力反转给了BeanFactory,当Spring运行的时候就回去配置文件中找配置的bean,然后创建相应的bean。
可以将创建bean的时候,然后依赖注入用到了IoC,这个过程详见bean生命周期,然后这个依赖注入是使用反射实现的。反射可以获取一个类中的对象和属性,然后动态的将对象创建和注入。可以多讲讲反射。
面向切面编程,能够将那些与业务无关的模块封装起来,像事务,日志,可以减少系统的重复代码,降低模块间的耦合度,并有利于未来的可维护性和可扩展性。
简单来说AOP就是保证开发者在不破坏源码的情况下,为系统中的业务组件添加功能。其中用到了动态代理。
编程式事务(不推荐使用),通过手动管理事务,实际应用很少使用。
声明式事务,在xml配置文件中直接基于注解,实际是通过AOP实现的。
失效场景:修饰一个非public方法,方法中异常被try catch捕获,数据库不支持事务,不是Spring框架创建的类。
使用数据库默认的隔离级别,读未提交(事务读取其他事务未提交的数据),读已提交,可重复读(同义事务中,任何时刻查询的结果一致),依次执行。
@Service、@Repository、@Controller,@Component(表示Spring管理的组件),@Autowired(自动装配依赖注入),@Configuration(标识配置类),@Bean,@Scope(指定Bean作用域),@Transactional(事务),@RequestMapping(请求映射),@Aspect(定义切面)。
@Autowired和@Resource的区别,是一个是spring注解,一个是jdk注解。
Bean对象创建–>销毁的一个过程,销毁一般是自动或手动配置,主要说Bean实例化–> 反射创建对象–>Bean称为完整对象,最终存储在单例池(singlentonObjects)中。
@Component替换bean标签,之前启动时会先去xml中加载bean,现在优先加载@Component注解。凡是被@Component注解标识的类,会在指定范围内被Spring加载并实例化。
使用注解标签可以替换bean上面的配置,使得Spring加载更加的便洁,在使用上,之前配置xml文件,配置bean对象的话是需要在bean的配置上配置相应的功能,比如scope,在使用注解时直接使用@Scope注解标签向需要标注的方法上标注作用范围,在bean中的lazy-init在注解标签中使用@Lazy,bean中的init-method在注解中直接向需要加载的方法上标注@PostConstruct,bean中的destroy-method在注解标签中使用@PreDestroy直接在对应的方法上标记。
配置类用来替代配置文件,使用@Configuration注解标签标识,在配置类中配置相应的配置,然后使用注解方式加载Spring的核心配置类,省去了写xml配置文件,相当于将需要的配置使用相应的注解全部配置在配置类中,然后启动时直接加载配置类就行。
注入双向对象引用属性,就是两个对象相互引用,在注入过程中,当某一个Bean执行过程中另一个Bean没有执行,创建了第一个bean的对象后(内存中存在,singletonObjects中没有),然后第一个Bean需要进行属性注入,发现第二个bean没有创建,然后暂停创建第二个bean,这时候第二个bean 同样执行创建对象,然后依赖注入,发现单例池中没有第一个bean,这时候就会暂停去创建第一个bean,这时候就造成循环引用问题,这时候想要解决就需要第二个bean注入第一个bean的时候不用去单例池中去查找,需要直接将第一个bean创建对象时的地址直接引用进来,然后继续走后面的流程,两者都会解决这个循环依赖问题。这个时候就需要使用三级缓存这个是Spring提供的专门解决循环依赖问题的。
因此初始化阶段如果遇到循环依赖问题,Spring中会使用三级缓存解决,在三级缓存中,有个类singletonFactories用来存储创建的对象,但是存储的是半成品对象,且没有被引用,二级缓存(earlySingletonObjects)存储的是新创建的对象,但是已经被引用,一级缓存存储的是已经创建完成的对象。在解决循环依赖时,当第一个bean创建对象,存储在三级缓存中,然后第一个bean进行属性注入时,去三个缓存中搜索第二个bean,发现没有,所以需要去创建,创建了第二个bean对象,存储在三级缓存中,然后第二个bean去注入第一个bean,去三个缓存中寻找,在第三个缓存中找到,然后进行注入,将第一个bean从三级缓存放入二级缓存,然后继续第二个bean的生命周期,直到完全创建成功,创建完成的第二个bean放入一级缓存,然后删除二三缓存中的第二个bean,然后继续执行第一个bean,将第二个bean注入第一个bean中,然后执行剩余的生命周期,完成第一个bean的创建,将其存入一级缓存,然后删除二三缓存中的第一个bean。
AOP面向切面编程,面向对象OOP是对一个事物的抽象,一个对象包括静态的属性信息、动态的方法信息等。而AOP是横向的,是对不同事物的抽象,属性与属性,方法与方法,对象与对象都可以组成一个切面,这种思维去设计编程就是面向切面编程,要想实现这一思想,就需要使用到动态代理,动态代理就是无侵入式的给代码增加新的功能,通过接口保证后面的对象和代理实现同一个接口,接口就是被代理的所有方法,然后代理类可以对需要代理的对象增加新的功能,代理同名方法内的同时,可以执行原有逻辑同时嵌入其他逻辑或其他对象方法。
之前知道动态代理,就是将一个类的需要代理的方法通过创建一个接口,然后实现代理类的方式去创建代理对象,然后向代理对象中添加新的功能或者其他对象中的方法来实现动态代理的功能。但是面向切面中有以下几点概念,有:目标对象,代理对象,连接点,切入点,同时/增强功能,还有切面,其中目标对象就是需要进行增强,进行代理的对象,连接点就是其中的方法,切入点就是其中需要进行代理的方法,代理对象就是使用Proxy对象来进行代理,将需要代理的方法传入Proxy的参数中,通知/增强部分就是需要添加的方法或事件,切面部分是对于每一个被增强的方法而言的。
在Spring中在调用getProxy方法的时候,可以选用的AopProxy接口有两个实现类,一种是基于JDK的,另一种是基于Cglib的
首选的都是jdk基于接口的,就是目标类有接口,基于接口实现动态规划,生成实现类的对象,这种是目标类有接口的情况下,默认方式。
其次是Cglib动态代理,使用Cglib的情况就是当这个目标类没有接口的时候,这个时候系统自动创建一个类去继承这个目标类,然后在创建的类中去实现增强功能,这种方式是当目标类没有接口的情况下默认实现,目标类有接口的时候,想要使用需要手动配置。
BeanFactory是Spring早期的接口,是Bean工厂,主要是管理Bean,而ApplicationContext是后期更高级的接口,称为Spring容器。ApplicationContext是对BeanFactory基础的功能上进行了扩展,BeanFactory的API更偏向于底层,而ApplicationContext的API更像是将底层API进行封装;Bean的创建的主要逻辑和功能都被封装在BeanFactory中,所以ApplicationContext继承BeanFactory,又维护着BeanFactory的引用,就说说BeanFactory是ApplicationContext中的一个属性。最后就是两者的对于Bean的初始化的时机不同,原始BeanFactory是在首次调用getBean是才进行创建,而ApplicationContext是在配置文件加载,容器一创建就将Bean都实例化并初始化好的。