一、Spring简介
Spring是轻量级的开源JavaEE框架,解决企业应用开发的复杂性
框架使用时需要引入相关的依赖(架包),在Spring中jar包数量比较小,体积也比较小所以说他是轻量级
Spring有两个核心部分控制反转(IOC)和面向切面编程(AOP)
(1)IOC:控制反转,把创建对象过程交给Spring进行管理(IOC创建的对象叫做Bean)IOC详解
(DI:依赖注入,在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入,也就是使用对象时不仅可以直接从IOC容器获取,还可以同时获取到该对象绑定的依赖关系)
(2)AOP:面向切面,不修改源代码进行功能增强
- 优点
- 方便解耦合,简化开发
- AOP编程支持
- 方便进行事务操作
- 方便程序测试
- 方便集成各种优秀框架
二、Spring快速入门
步骤
-
导入Spring开发的基本坐标(导入context的其他的会自动帮我们下载)
-
定义Spring管理的类(接口)(编写Dao接口和实现类)
-
配置Bean
-
获取IOC容器(初始化容器),获取Bean
三、XML配置
1、bean默认单例模式
为什么默认是单例模式呢,因为Spring的空间也是有限的,如果是多例的每次都创建一个新对象这样很消耗内存,而且访问速度也会变慢,单例模式也会引起线程同步的问题(多个线程同时并发执行)
注意:
当scope取值是singleton时,Bean实例化数量1个
Bean实例化的时机:当spring核心配置文件被加载时,实例化配置的Bean实例
当scope取值是prototype时,Bean实例化数量多个
Bean实例化的时机:当调用getBean()方法,实例化配置的Bean实例
2、bean实例化三种方式
-
无参构造方法实例化
-
工厂静态方法实例化
-
工厂实例方法实例化
3、bean生命周期
bean生命周期:bean从创建到销毁的整个过程
bean声明周期的控制
-
当scope的取值为singleton时。
Bean实例化个数:1个
Bean实例化时机:当spring核心文件被加载时,实例化配置的bean实例
Bean声明周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了 -
当scope的取值为prototype时。
Bean实例化个数:多个
Bean实例化时机:当调用getBean()方法时,实例化配置的bean实例
Bean声明周期:
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被Java的垃圾回收器回收了
4、bean的依赖注入
- setter方法注入(引用类型)
- 构造器注入(引用类型)
-
setter方法——属性注入普通类型
-
setter方法——属性注入引用类型
-
setter方法——集合注入
引入其他配置文件
四、数据源开发步骤
-
1、导入数据库驱动坐标和数据源坐标
-
2、创建数据源对象
-
3、设置数据源的基本连接数据
-
4、使用数据源获取连接资源和归还连接资源
五、注解配置
使用注解开发时需要在xml文件中配置组件扫描,来识别注解
@Component:组件,可以定义所有bean
@Component的三个衍生注解
@Repository: 主要用于定义数据( dao )层的 bean(repository仓库的意思,数据库相当于一个仓库)
@Service: 主要用于定义业务(service)层的 bean
@Controller: 主要用于定义表现(web)层的 bean
@Scope:bean的作用范围
- singleton:默认单例
prototype:多例
request
session
globalsession
@Autowired:注入引用类型,根据类型依赖注入
@Qualifier:根据名字进行依赖注入(不能单独使用,要搭配@Autowired一起使用)
@Resource: 默认按照名字进行注入,即会按照name属性的值来找到具有相同id的Bean并注入,如果没有指定name属性,Spring将使用变量名来查找,如果没找到会根据类型查找,如果根据类型找到多个用@Qualifier来指定。
@Value:注入普通属性
@PostConstruct:使用在方法上标注该方法是bean的初始化方法
@PreDestroy:使用在方法上标注该方法是bean的销毁方法
六、XML配置对比注解配置
七、AOP
1、AOP基本概念
AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
作用:在不改变原始代码的基础上对原代码进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
是一种基于OOP(Object Oriented Programming面向对象编程)的编程思想
概念图解
- Joinpoint连接点:可以被增强的方法叫做连接点
- Pointcut切入点:实际被增强的方法叫做切入点
- Advice通知:增强,若干个方法的共性功能
- Aspect切面:描述通知和切入点的对应关系
- Target目标对象:被代理的原始对象称为目标对象
- Proxy代理:SpringAOP的核心本质是采用代理模式实现的
- Weaving织入:切入点+通知结合生成代理的过程
开发编写步骤:
1.编写核心业务代码(目标类的方法)
2.编写通知类,通知类中有要增强的方法
3.在配置文件中,配置织入关系,即将哪些通知和哪些连接点进行结合
2、AOP的底层实现
实际上,AOP底层是通过Spring提供的动态代理技术实现的,在运行期间,spring通过动态代理技术动态的生成代理对象,代理对象执行时进行增强功能的介入再去调用目标对象方法,从而完成功能的增强。
- 常用动态代理技术:
JDK动态代理:基于接口的动态代理技术
Cglib动态代理:基于父类的动态代理技术
3、AOP入门案例
测定接口执行效率,在接口执行前输出当前系统时间
开发模式:注解
步骤:
- 导入坐标(pom.xml)
- 制作连接点方法(原始操作,Dao接口与实现类)
- 制作共性功能(通知类与通知)
- 定义切入点(要给谁增加功能谁就是切入点)
- 绑定切入点与通知的关系(切面)
接下来我们来增强update方法,给他加上打印系统当前时间的方法,在不改变原始代码的情况下进行功能增强
1.导入坐标(pom.xml)
2.制作连接点方法(原始操作,Dao接口与实现类)
3.制作共性功能(通知类与通知)这里也就是打印系统时间的功能
4.定义切入点(要给谁增加功能谁就是切入点)
5.绑定切入点与通知的关系(切面)
在通知类上加上注解
配置配置文件让spring扫描AOP注解
运行结果
对应的XML配置
<!-- 配置bean标签-目标对象 --><!-- 相当于@Component -->
<bean id="bookDao" class="com.chinasofti.dao.BookDao"></bean>
<!-- 配置bean标签-切面对象 --><!-- 就是通知对象 -->
<bean id="myAdvice" class="com.chinasofti.aop.MyAdvice"></bean>
<!-- 配置织入:告诉spring框架,哪些方法(切点)需要进行增强(通知,例如:前置..后置) -->
<aop:config>
<!-- 声明切面 --><!-- 相当于@Aspect,标注当前的类是一个切面类 -->
<aop:aspect ref="myAdvice">
<!-- 切面:通知+切点 -->
<!--
切点表达式的写法:
语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
1、修饰符可以省略
2、返回值类型、包名、类名、方法名可以使用*,代表任意
3、包名与类名之间一个点,代表当前包下的类,两个点..代表当前包及其子包下的类
4、参数列表可以使用两个点..表示任意个数,任意类型的参数
-->
<!-- <aop:before method="before" pointcut="execution(public void com.chinasofti.dao.impl.BookDaoImpl.update())"/> -->
<!-- <aop:before method="before" pointcut="execution( void com.chinasofti.dao.impl.BookDaoImpl.update())"/> -->
<!-- <aop:before method="before" pointcut="execution( * com.chinasofti.dao.impl.BookDaoImpl.update())"/> -->
<aop:before method="before" pointcut="execution( * com.chinasofti.dao.*.*(..))"/>
<!-- <aop:before method="before" pointcut="execution( * com.chinasofti.*.*.*(..))"/> -->
<!-- <aop:before method="before" pointcut="execution( * *..*.*(..))"/> -->
<!-- 切点表达式的抽取 -->
<aop:pointcut expression="execution( * com.chinasofti.dao.*.*(..))" id="myPoint"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPoint"/>
<aop:around method="around" pointcut-ref="myPoint"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPoint"/>
<aop:after method="after" pointcut-ref="myPoint"/>
</aop:aspect>
</aop:config>
5、AOP切入点表达式
切入点:要进行增强的方法
切入点表达式:要进行增强的方法的描述方式
- 描述方式一:执行com.chinasofti.dao包下的BookDao接口中的无参数update方法
execution(void com.chinasofti.dao.BookDao.update()) - 描述方式二:执行com.chinasofti.dao.impl包下的BookDaoImpl类中的无参数update方法
execution(void com.chinasofti.dao.impl.BookDaoImpl.update())
切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类名/接口名.方法名(参数)异常名)
访问修饰符和异常名可省略
使用通配符描述切入点
- *:匹配任意字符
- …:匹配多个连续的任意字符
- +:匹配子类类型
6、AOP通知类型
- 1、前置通知
- 2、后置通知
- 3、环绕通知(重点)
- 4、返回后通知
- 5、抛出异常后通知
前置通知和后置通知
3、环绕通知(重点)
要解决原始方法没有执行的问题,需要在@Around注解上加上参数,并且还要调用原始方法
这样虽然是解决了,但是运行结果给我们抛了个异常,是因为我们的select方法的返回值是int,二selectAround却是无返回值
改进后
4、返回后通知
5、抛出异常后通知
6、AOP获取通知的数据