Spring是什么?
Spring是一个轻量级的IOC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化咱们应用程序的开发。
Spring是一个开源框架,Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
为什么说Spring是一个一站式的轻量级开源框架呢?EE开发可分成三层架构,针对JavaEE的三层结构,每一层Spring都提供了不同的解决技术。
Spring的优点?
1.spring属于低侵入式设计,代码的污染极低;
2.spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
3.Spring提供了AOP技术,支持将一些通用任务,如事务、日志等进行集中式管理,提高代码复用。
4.spring对于主流的应用框架提供了集成支持。
从对Spring的简要介绍中,我们知道了Spring的核心有两部分:
- IoC:即控制反转,是指创建对象的控制权的转移,也就是咱们程序本身不再负责组件的创建、维护等,而是由spring容器负责。
举例来说,在之前的操作中,比方说有一个类,我们想要调用类里面的方法(不是静态方法),就要创建该类的对象,使用对象调用方法来实现。但对于Spring来说,Spring创建对象的过程,不是在代码里面实现的,而是交给Spring来进行配置实现的;
Spring的IoC的底层实现原理是工厂设计模式+反射+XML配置文件。
控制反转IOC是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方
比如转移交给了IOC容器,它就是一个专门用来创建对象的工厂(BeanFactory),你要什么对象,它就给你什么对象,有了
IOC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IOC容器了,通过IOC容器来建立它们之间的关系。
spring IOC管理的对象,我们称为bean。bean就是spring容器初始化,装配,及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别。那IOC如何实例化bean、管理bean之间的依赖关系?这些就需要配置元数据。
- AOP:即面向切面编程。
AOP(Aspect Oriented Programming),是面向切面编程的技术。aop采用的横向抽取机制,代替了传统纵向继承机制,提高代码复用性。
它是对OOP的有益补充。AOP将应用系统拆分为个部分:核心业务逻辑及横向的通用逻辑,也就是所谓的切面。
举例:所有大中型应用都要涉及到的持久化管理、事务管理、权限管理、日志管理和调试管理等。使用AOP技术可以让开发人员只专注核心业务,而通用逻辑则使用AOP技术进行横向切入,由专人去处理这些通用逻辑,会使得任务简单明了,提高开发和调试的效率。
Target:目标类
Joinpoint:连接点是指所有可能织入通知的方法理论上大部分方法都是连接点
Pointcut:切入点,已经被增强的方法 Advice:通知,增强的方法 Aspect:切面,通知所在的类就叫切面。
Weaving:织入,将通知应用到目标对象来创建新的代理对象的过程。
通知的类型: 前置通知 后置通知 返回通知 异常通知 环绕通知
各类通知的执行顺序: 前置通知 2.执行目标方法 3.执行后置通知 4.返回通知||异常通知
前置通知,后置通知,返回通知,异常通知都可以接受一个JoinPoint类型的对象作为参数。该对象封装了连接点的相关信息。主要关注:方法参数和方法签名。
返回通知的returning属性可以将目标方法的返回值定义一个名字,然后在返回通知的形参上声明一个同名的Object类型的参数,来访问方法的返回结果。
<aop:after-returning method=”afterReturnLog” pointcut-ref=”userDaoPointccut” returning=”result” /> 环绕通知 环绕通知必须要有返回值(Object类型)
环绕通知必须要有形参(ProceedingJoinPoint pjp)
在环绕通知中,通过pjp.proceed()方法显示调用目标对象的切点并将结果返回出去。
使用注解配置aop
引入约束 beans context aop 扫描包 开启注解式的aop <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
-
在业务类上加上注解(@Component)
在属性上加@Autowired注解
在切面类上加注解 (@Component @Aspect)
在通知上加上相应的注解 @Before(value="")
@AfterReturning(returning=“目标切点返回值的名字”) 在通知方法参数只能为Object
@AfterThrowing(throwing=“异常的名字”) 在通知方法参数可以为Object也可为Exception
重用切入点表达式: 在切面中定义一个空的方法,在方法上加@Pointcut注解,在value属性中指定切入点表达式 @Pointcut(value=“execution(* com.cdsxt.dao..(…))”) Public void pointcutExpression(){} @Before(value=“pointcutExpression()”)
在面对多个切面时可以在类上加@Order(1)数字越小越优先执行
AOP两种代理的区别:
AOP支持2种代理,jdk的动态代理和CGLIB实现机制。
jdk基于接口实现:jdk动态代理对实现了接口的类进行代理。
CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以目标类最好不要使用final声明。
通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB。
spring bean
获取spring的Ioc核心容器,并根据id获取对象
ApplicationContext的三个常用实现类:
-
ClassPathXmlApplicationContext :
它可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了。(常用) -
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
-
AnnotationConfigApplicationContext:它是用于读取注解创建容器的
核心容器的两个接口引发出的问题:
ApplicationContext: 单例对象适用 采用此接口
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建文件中配置的对象。
BeanFactory: 多例对象适用
它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
spring对bean的管理细节
-
创建bean的三种方式
-
bean对象的作用范围
-
bean对象的生命周期
创建bean的三种方式:
1.使用默认构造函数创建。
在spring配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
2.使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存如spring容器)
<bean id="xxx" factory-bean="xxx" factory-method="xxx"></bean>
3.使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
bean的作用范围调整:
bean标签的scope属性:
作用:用于指定bean的作用范围
取值:
singleton:单例(默认值)
prototype:多例
request:作用于web应用的请求范围
session:作用域web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
bean对象的生命周期
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
DI
依赖注入:Dependency Injection
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护:就称为依赖注入。
依赖注入:
能注入的数据:有三类
- 基本类型和String
- 其他bean类型(在配置文件中或者注解配置过的bean)
- 复杂类型 / 集合类型
注入的方式:有三种
-
第一种:使用构造函数提供
构造函数注入:
使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性:
type:用于指定要注入的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数复制。索引的位置是从0开始
name:用于指定给构造函数中指定名称的参数赋值-------- 常用
------------------------上面三个用于指定给构造函数中哪个参数赋值
value:用于提供基本类型和String 类型的数据
ref:用于指定其他的bean类型数据。他只得就是在spring的ioc核心容器中出现过的bean对象
特点/优势:
在获取bean对象时,注入数据是必须的操作,否则对象就无法创建成功
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供 -
第二种:使用set方法提供
set方法注入
使用的标签:property
标签出现的位置:bean标签的内部
标签中的属性:
name:用于指定注入时所调用的set方法的名称------- 常用
value: 用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
如果有某个成员必须有值,则获取对象时set方法没有执行
复杂类型的注入/集合类型的注入
用于给List结构集合注入的标签:
list array set
用于给Map结构集合注入的标签:
map props
结构相同,标签可以互换 -
第三种:使用注解提供
使用注解:
要改xml的约束
IOC注解按作用分类:
用于创建对象的:
它们的作用就和在XML配置文件中编写一个标签实现的功能是一样的
component:
作用:用于把当前类对象存入spring容器中
属性:value:用于指定bean的id。当我们不写时,默认值是当前类名,且首字母改小写
Controller
Service
Repository
以上三个注解他们的作用和属性与Component是一模一样的
它们三个是spring框架为我们提供明确的三层使用的注解。使我们的三层对象更加清晰
用于注入数据的
它们的作用就和XML配置文件中的bean标签中写一个标签的作用是一样的
Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
出现位置:可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了
Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以
Resource:
作用:直接按照bean的id注入。它可以独立使用
属性:name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据。而基本数据类型和String类型无法通过以上注解实现,另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEl(也就是spring的el表达式) SpEl的写法:${表达式}
用于改变作用范围的
他们的作用就和在bean标签中使用scope属性实现的功能是一样的
Scope
作用:用于指定bean的作用范围
属性:value:指定范围的取值。常用取值:singleton prototype
和生命周期相关 了解
它们的作用就和在bean标签中使用init-method和destroy-method的作用是一样的
PreDestroy
用于指定销毁方法
PostConstruct
用于指定初始化方法
*