Spring框架的学习IOC与AOP及声明式事务

Spring的官网

Spring由IOC与Aop组成

Spring简介:

Spring IOC【Inverse Of Control】

DI全称:Dependency Injection:依赖注入,IOC是一种思想,DI是具体实现

Spring AOP【Aspect Oreinted Programming】

事务

Spring简介:

Spring是一个基于IOC【Inverse Of Control】和Aop【Aspect Oreinted
Programming】的企业级开发框架,框架本身就是简化开发的

Spring在软件三层架构中的位置

Spring在软件三层架构中的位置

Spring的模块介绍在这里插入图片描述

Spring的IOC【控制反转】

定义: 全称Inverse Of Control: 反转控制,指的是将bean对象的创建及bean对象关联关系的维护
由原来我们创建、自己维护对象的关联关系反转给了spring的容器来创建对象及维护关联关系。 解决:
解决了上层建筑严重依赖下层建筑的问题,实现了上层建筑对下层建筑的控制。
底层实现: xml解析 + 反射 + 容器 + 设计模式

容器中bean对象的创建时机、底层原理、是否单例

容器中bean对象的创建时机、底层原理、是否单例
1.创建时机: 默认是在容器加载的时候,容器中的bean对象按着从上到下的顺序依次被创建出来
2 底层原理:反射
3是否单例: 默认是单例的,如果想改成多例的,需要设置bean标签的scope属性值scope:
singleton:默认值,表示该对象是单例的,是随着容器的加载该bean对象被创建出来
prototype:多例的,该对象是我们从容器中获取bean对象的时候才被创建,而不是随 着容器的加载该对象被创建出来。
request:表示每个request请求都会创建一个新的bean对象
session:表示每个session会话都会创建一个新的bean对象

分模块配置

<import resource="classpath:applicationContext-email.xml"/>

内部bean与外部bean

外部bean:在beans标签内部定义的bean对象都称之为外部bean,外部bean可以被多个bean对象引用
内部bean:在bean标签内部定义的bean对象,内部bean只能被某个对象的某个属性引用

创建对象的三种方式

创建对象的三种方式:
1.构造器【有参构造器、无参构造器】
2.静态工厂:通过类的静态方法返回的对象
3.实例工厂:通过类对象的普通方法返回的对象
1.1构造器【有参构造器、无参构造器】
<bean class="com.offcn.bean.Book">
     <constructor-arg name="bid" value="100"></constructor-arg>
     <constructor-arg name="bookName" value="三国演义"></constructor-arg>
     <constructor-arg name="price" value="89.9"></constructor-arg>
  </bean>
2.静态工厂:通过类的静态方法返回的对象
<bean id="book" class="com.offcn.bean.StaticFactory" factory-method="getBook"></bean>
3. 实例工厂:通过类对象的普通方法返回的对象
  <bean id="instance" class="com.offcn.bean.InstanceFactory"></bean>
  <bean id="book01" factory-bean="instance" factory-method="getBookInfo"></bean>

给对象属性赋值的三种方式

在这里插入图片描述

复杂属性注入

对于数组类型的属性:使用Array标签给属性赋值
<bean class="com.offcn.bean.FlexBean">
    
   <property name="arr">
       <array>
          <value>1</value>
          <ref bean="book01"/>
          <bean class="com.offcn.bean.Book">
            <property name="bookName" value="三国演义"></property>
          </bean>
       </array>
     </property>
对于list类型的属性,使用List标签
<property name="list">
        <list>
          <value>2</value>
          <ref bean="book01"/>
        </list>
	</property>
对于SET类型的属性,使用set标签
   <property name="set">
        <set>
          <value>3</value>
          <ref bean="book01"/>
        </set>
     </property>
对于Map类型的属性,使用Map标签嵌套entry标签
<property name="map">
        <map>
          <entry key="key1" value="value1"></entry>
          <entry key-ref="book01" value="value2"></entry>
          <entry key="key3" value-ref="book01"></entry>
          <entry key-ref="book02" value-ref="book01"></entry>
        </map>
	</property>
对于Properties类型的属性,使用props标签嵌套prop标签
     <property name="properties">
        <props>
           <prop key="key1">value1</prop>
           <prop key="key2">value2</prop>
           <prop key="key3">value3</prop>
        </props>
     </property>
   </bean>

SPEL全称:Spring Expression Language:Spring的表达式语言,简称:SPEL表达式

语法:#{}
支持:使用字面量
普通对象
普通对象的普通属性
普通对象的普通方法
类的静态属性
类的静态方法
各种各样的运算符

几个常用的其它注解

@Controller:表示该类对象是控制层[web层]的一个组件
@Service:表示该类对象是业务逻辑层[service层]的一个组件
@Repository:表示该类对象是持久化层[dao层]的一个组件
@Component:表示该类对象是容器中的一个普通组件

使用注解的方式给对象的属性赋值

@Value:给基本类型的属性赋值,用value注解

在这里插入图片描述

@Autowire:给引用类型的属性赋值,用Autowire注解,Spring的注解
@Resource:给引用类型的属性赋值,用Resource注解,JDK自带的
说明:
@Autowire:先根据该属性的类型去容器中找该类型的唯一bean对象,如果有唯一bean对象就将该容器中的唯一bean对象赋值给该属性,如果没有,报错,或者容器中有多个该该类型的bean对象,再根据Autowire注解标记的属性名去容器中找,看看容器中的哪个bean对象的id值和该属性名一致,如果有,就将容器中的这个对象赋值给该属性。
@Resource注解的使用类似于上面的@Autowire注解

Spring 的Aop[面试]

全称:Aspect Oreinted Programming:面向切面编程,简称Aop

Object Oreinted Programming: 面向对象编程:简称OOP 软件工程有个基本的概念,叫做关注点分离 关注点分离[Separation of Concerns]: 不同的问题交给不同的部分去解决,每部分专注于解决自己的问题
面向切面编程AOP正是此种技术的实现!
比如:我们写业务代码的时候还要写事务管理、缓存、日志等等通用化的功能,而且这些通用化的功能和这些业务逻辑混在一起!
所以为了将业务逻辑功能的关注点和这些通用化功能的关注点分离开来,就出现了Aop的技术!
通用化功能代码的实现,对应的就是所谓的切面【Aspect】 业务代码和通用功能代码分离之后,责任明确,架构就能变得高内聚低耦合
定义:全称:Aspect Oriented Programming,面向切面编程,和OOP相互促进、相互补充的关系
**是在OOP原有类代码的基础上,在不改变源代码的前提下,对原有类的功能 进行拓展。
解决:解决了软件工程中提出的关注点分离问题,让不同的部分解决不同的问题。 底层实现:cglib代理 + jdk动态代理
具体应用:声明式事务、缓存、日志处理、全局异常处理。

Aop涉及到的几个重要概念

通知【Advice】:被拓展的功能,称之为通知【本质:方法】**
切面【Aspect】:通知所在的类,称之为切面【本质:类】
切入点【PointCut】:指定对谁进行拓展【本质:表达式】
连接点【JoinPoint】:通知和目标方法的交点,称之为:连接点
目标对象【Target】:被拓展的类对象,称之为目标对象
织入【Weaving】: 将通知 应用到 目标方法的过程,称之为织入

图解Aop中涉及到的几个概念

在这里插入图片描述

Aop的底层原理

在这里插入图片描述

代理:

代理类都是在不改变被代理类代码的基础之上对被代理类的功能进行拓展。 静态代理 静态代理:只能代理某一个接口的实现类
Alipay:代理,而且是在不改变真实用户代码的基础之上对真实用户功能的拓展
静态代理:弊端只能代理某个接口的实现类

JDK动态代理

动态代理:可以代理任意接口的实现类

静态代理和动态代理的区别

**相同点:
1.都是在不改变被代理类代码的基础上对被代理类的功能进行拓展
2.都实现了接口 不同点:
1.静态代理只能代理某个接口的实现类,动态可以代理任意接口的实现类

切面的五种通知

前置通知[@Before]:在目标方法执行之前执行
后置通知[@After]:无论目标方法有没有执行成功,后置通知都会执行。
返回通知[@AfterReturning]:只有在目标方法执行成功的情况下,返回通知才会执行
异常通知[@AfterThrowing]:只有在目标方法出现异常的情况下,异常通知才会执行。
环绕通知[@Around]:以一敌四。

切面通知底层结构 try catch 内层嵌套try finally

在这里插入图片描述

切入点表达式

语法:

方法签名:[权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表]
execution([权限修饰符] [返回值类型] [简单类名/全类名] 方法名

重用:

@Component
@Aspect
public class LogAspect {

	@Pointcut(value ="execution(* *.*(..))")
	public void pointCut() {}
	
	//切入点表达式
	@Before(value = "pointCut()")
	public void beforeLog() {
		System.out.println("日志切面 前置通知.......");
	}
}
拓展:
最简洁切入点表达式[最模糊]:
 execution(* *.*(..))
最复杂的切入点表达式[最精确]:
execution(public int com.offcn.func.CaculatorImpl.add(int, int, int))
注意:在AspectJ中,切入点表达式可以通过 “&&”、“||”、“!”等操作符结合起来

使用环绕通知实现事务切面

public class TransactionAspect {
	//环绕通知注意点:环绕通知的方法必须返回Object类型的参数
	//@Around(value = "execution(public int com.offcn.func.CaculatorImpl.add(int, int))")
	public Object around(ProceedingJoinPoint proceedingJoinPoint){
		Object proceed=null;
		try {
			try {//1、前置通知: 开启事务
				System.out.println("事务切面 ---------------->前置通知");
				//实际调用了目标方法
				proceed = proceedingJoinPoint.proceed();
			}finally {
				System.out.println("事务切面 ---------------->后置通知");
			}
			//3.返回通知----> conn.commit();
			System.out.println("事务切面 ---------------->返回通知");
		}catch (Throwable e) {
			//4.异常通知---->conn.rollback();
			System.out.println("事务切面 ---------------->异常通知");
		}
		return proceed;	
	}
}

多切面情况下的通知的执行顺序问题

分了三种情况:
1.目标方法不出异常
2.目标方法出了异常,但是内层切面没有把异常抛出
3.目标方法出了异常,内层切面把异常抛出了

多切面情况下切面优先级问题

多切面情况下切面的优先级问题,是由标记在切面类上order注解的value属性值决定的,value值越小,优先级越高

事务

事务简介:

在同一个功能单元,如果涉及到对数据库的多次操作【转账】,而且要求这多次操作要么同时成功,要么同时失败,这时候有必要使用事务

编程式事务

Connection conn= JdbcUtils.getConnection();
try{
conn.setAutoCommit(false);------>1.开启事务
------->2.给数据库发送SQL语句
------->3.提交事务

}catch(Exception ex){
                            ------->4.回滚事务
}finally{
                            ------->5.释放资源
}

声明式事务

这里所说的声明,就是指在配置文件中声明。用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。这样的好处是,事务管理不侵入开发的组件,具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可;在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便

声明式事务的五大属性【拓展】

Propagation:传播机制:一个带有事务的方法A运行在另一个带有事务的方法B的内部的时候,内层方法A是使用自己的事务还是使用外层方法B的事务。

取值: required、requires_new、supports

Required【默认值】:

如果外层方法有事务,就用外层方法的事务 如果外层方法没有事务,内层方法就自己开一个新的事务。

requires_new: 无论外层方法有没有事务,内层方法都用自己的事务

Supports:

如果外层方法有事务,就用外层方法的事务,
如果外层方法没有事务,内层方法就不用事务了。
Isolation: 隔离级别: 针对数据库的并发访问

Read_uncommited:读未提交

Read_commited:读已提交

Repeatable_read:[默认值]可重复读:在一个事务内多次读取的数据表的数据是一致的。

Serializable: 串行化读

这四个隔离级别,按着从上到下的顺序,并发度越来越低,但是安全性越来越高。

rollbackFor:回滚属性:

事务默认只是在遇到RuntimeException才会回滚,如果遇到了编译时异常, 默认是不会回滚的,如果想让编译时异常回滚,就要是rollbackFor属性,同理,对于 有些运行时异常【RuntimeException】如果不想让它回滚,可以设置norollbackFor属性

Timeout: 超时属性

事务在运行过程中,势必会占用数据库的资源,如果一个事务长时间运行,就会导致数据 库的资源长时间被占用,就会影响其它事务的执行,所以为了不让某个事务长时间占用
数据库资源,我们可以为事务设置超时属性,当在规定的时间内,如果一个事务还没 有执行成功,就让该事务回滚。

readOnly: 只读属性:加快访问速度

True: 在该方法中,就不能对数据库进行增删改操作。
False:

数据库的锁:

共享锁:
排它锁:

基于xml的声明式事务

  <aop:config>
     <!-- 1.指定切入点表达式 -->
     <aop:pointcut expression="execution(* com.offcn.service.BookService.*(..))" id="myPointCut"/>
     <!-- 2.将事务和切入点表达式联系起来 -->
     <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut"/>
  </aop:config>
   <!-- 配置基于xml的声明式事务 -->
   <tx:advice id="myAdvice" transaction-manager="transactionManager">
      <tx:attributes>
         <tx:method name="buy*" />
         <tx:method name="get*" read-only="true"/>
         <tx:method name="find*" read-only="true"/>
         <tx:method name="query*" read-only="true"/>
         <tx:method name="update*" isolation="DEFAULT"/>
         <tx:method name="modify*" isolation="DEFAULT"/>
         <tx:method name="insert*" isolation="DEFAULT"/>
         <tx:method name="delete*" isolation="DEFAULT"/>
      </tx:attributes>
   </tx:advice> 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值