框架 day37 Spring3,AOP,代理模式(动态/CGLIB/工厂bean),传统AOP,AspectJ框架(基于xml/注解),切入点表达式,jdbcTemplate
2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
* 程序中应优先对接口创建代理,便于程序解耦维护
* 标记为final的方法,不能被代理,因为无法进行覆盖
? JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
? CGLib 是针对目标类生产子类,因此类或方法 不能使final的
* Spring只支持方法连接点,不提供属性连接
3 spring工厂bean,半自动(了解)3.1 aop联盟通知类型
* 使用spring提供 FactoryBean创建代理对象,手动的获取代理对象。生成代理需要应用增强(通知),通知需要确定方法名称。spring规范规定通知类型,从而确定方法名称。
* aop联盟确定5中通知类型,spring对aop联盟进行支持。
前置通知org.springframework.aop.MethodBeforeAdvice
在目标方法执行前实施增强
后置通知org.springframework.aop.AfterReturningAdvice
在目标方法执行后实施增强
环绕通知org.aopalliance.intercept.MethodInterceptor【】
在目标方法执行前后实施增强
异常抛出通知org.springframework.aop.ThrowsAdvice
在方法抛出异常后实施增强
引介通知org.springframework.aop.IntroductionInterceptor(了解)
在目标类中添加一些新的方法和属性
环绕
try{
前置
//必须手动执行目标方法
后置
} catch(){
//异常抛出
}
3.2 使用代理工厂bean
3.2.1 导入jar包
spring: 4个核心 + 1个依赖
springaop联盟:com.springsource.org.aopalliance-1.0.0.jar
springaop 实现:spring-aop-3.2.2.RELEASE.jar
3.2.2 目标类和接口
public class UserServiceImpl implements UserService {@Overridepublic void addUser() {System.out.println("factorybean add user");}@Overridepublic void updateUser() {System.out.println("factorybean update user");}}
3.2.3 编写切面类
* 必须遵循 aop联盟规范,通知需要实现相应接口
/** * 切面类,用于存放通知,使用的aop联盟规范,必须实现接口,从而确定方法名称(及spring如果执行通知) * */public class MyAspect implements MethodInterceptor{@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {System.out.println("前");//环绕通知,必须手动的执行目标方法Object obj = mi.proceed();System.out.println("后");return obj;}}
3.2.4 编写 spring配置
* 确定目标类 和切面类,通过spring提供ProxyFactoryBean生成代理类,将目标类和切面类进行结合。
通过属性注入的方式进行。
<!-- 1 创建目标类 --><bean id="userServiceId" class="com.itheima.b_factorybean.UserServiceImpl"></bean><!-- 2创建切面类(通知) --><bean id="myAspectId" class="com.itheima.b_factorybean.MyAspect"></bean><!-- 3 生成代理对象,目的:将目标类与切面类结合 * ProxyFactoryBean :生成一个特殊代理bean。* interfaces 确定接口,需要使用value* target 确定目标类,需要使用ref(对目标类的引用)* interceptorNames 确定通知所在类中名称,只需要名称不需要对象。需要使用value* optimize 确定是否使用cglib生成代理,true是,默认是false。--><bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 3.1 确定接口 --><property name="interfaces" value="com.itheima.b_factorybean.UserService"></property><!-- 3.2 确定目标类 --><property name="target" ref="userServiceId"></property><!-- 3.3 确定通知 ,使用切面类名称--><property name="interceptorNames" value="myAspectId"></property><!-- 3.4 强制使用cglib --><property name="optimize" value="true"></property></bean>
3.2.5 测试
@Testpublic void demo02(){//从工厂(spring)获得代理对象String xmlPath = "com/itheima/b_factorybean/beans.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);UserService userService = (UserService) applicationContext.getBean("proxyServiceId");userService.addUser();userService.updateUser();}4 spring传统aop开发(掌握)
* 从spring容器获得目标类,进行aop配置从而让spring创建代理类。全自动过程。
* 需添加aop命名空间
* 使用aspectj 切入点表达式,需要导入jar包
* spring配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 1 创建目标类 --><bean id="userServiceId" class="com.itheima.c_aop.UserServiceImpl"></bean><!-- 2创建切面类(通知) --><bean id="myAspectId" class="com.itheima.c_aop.MyAspect"></bean><!-- 3 spring 传统aop开发,使 通知 引用到 目标类切入点上 * 添加aop命名空间* aop 编程 <aop:config>* <aop:pointcut> 用于声明切入点,确定目标类上的那些方法将被增强。id : 切入点名称expression : 用于编写切入点表达式 (aspectj 切入点表达式)execution(* com.itheima.c_aop.*.*(..))固定返回值类型包类名方法名参数列表* <aop:advisor> 特殊的切面,只有一个切入点和一个通知advice-ref:一个通知引用pointcut-ref:一个切入点引用--><aop:config><aop:pointcut expression="execution(* com.itheima.c_aop.*.*(..))" id="myPointCut"/><aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/></aop:config></beans>5 AspectJaop框架(掌握)5.1 AspectJ介绍
* AspectJ是一个基于Java语言的AOP框架
* Spring2.0以后新增了对AspectJ切入点表达式支持
* @Aspect是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
新版本Spring框架,建议使用AspectJ方式来开发AOP
* 导入jar包:
aop联盟:com.springsource.org.aopalliance-1.0.0.jar
springaop支持:spring-aop-3.2.0.RELEASE.jar
aspect规范:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
springaspect 支持:spring-aspects-3.2.0.RELEASE.jar
1.execution:匹配方法的执行(常用)
格式:execution(修饰符 返回值类型 包.类名.方法(参数) throws 异常)
1.1修饰符,表示方法的修饰符,一般省略。
1.2返回值类型
String 表示返回String
void 表示没有返回值
* 表示返回任意类型【】
1.3包
com.itheima.service 表示指定的包
com.itheima.crm.*.service 表示crm的子模块,名称任意。
(例如:com.itheima.crm.user.service)
com.itheima.service.. 表示service目录,及子目录
综合:com.itheima.crm.*.service.. --> service / service.impl
1.4类名
UserService 表示指定的类
*Service 表示以Service结尾
Test* 表示以Test开头
* 表示任意类名
1.5方法名(与类名类似)
addUser 表示指定方法
add* 表示以add开头
*Do 表示以Do结尾
* 表示任意
1.6参数列表
() 表示没有参数
(int) 表示一个参数int类型
(int,int) 表示两个参数int类型
(如果是java.lang包下的可以省略,其他都必须是全限定类名)
(..) 表示参数任意
1.7throws 异常, 一般省略。
综合:execution(*com.itheima.crm.*.service..*.*(..)) ↓↓↓ 匹配↓↓↓
com.itheima.crm.user.service.impl.UserService.addUser(Useruser)
2.within:匹配包或子包中的方法(了解)
within(cn.itcast.aop..*)
3.this:匹配实现接口的代理对象中的方法(了解)
this(cn.itcast.aop.user.UserDAO)
4.target:匹配实现接口的目标对象中的方法(了解)
target(cn.itcast.aop.user.UserDAO)
5.args:匹配参数格式符合标准的方法(了解)
args(int,int)
6.bean(名称) ,匹配指定的bean(了解)
bean("userServiceId")
5.3 AspectJ规定通知类型
* 共6个,知道5个,掌握1个。
1.before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
2.afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
3.around:环绕通知(应用:十分强大,可以做任何事情) 【】
方法执行前后分别执行,可以阻止方法的执行。要求必须手动的执行目标方法。
4.afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
5.after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
环绕(around)
try{
//前置(before)
//手动执行目标类方法
//后置(afterReturning) --可以获得返回值
} catch(){
//抛出异常(afterThrowing) --可以获得具体的异常信息
} finally{
//最终(after)
}
5.4 基于xml aspectj
* aspectj通知类型 通过配置文件确定,没有具体接口。通知方法任意。
* xml配置
>常用属性
? pointcut:配置切入点表达式
? pointcut-ref:配置切入点引用对象
? method:配置切入点执行的通知方法
>JoinPoint连接点的信息
接口:org.aspectj.lang.JoinPoint
? 目标对象:getTarget()
? 获得方法签名:getSignature()
? 获得方法名称:getSignature().getName()
? 获得实际参数:getArgs()
? 获得当前指定方法的类型:getKind()
? method-execution 方法执行、
? constructor-execution构造方法执行
? field-get get方法
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 1 创建目标类 --><bean id="userServiceId" class="com.itheima.d_aspect.a_xml.UserServiceImpl"></bean><!-- 2创建切面类(通知) --><bean id="myAspectId" class="com.itheima.d_aspect.a_xml.MyAspect"></bean><!-- 3 aspect 编程 <aop:config> aop 编程proxy-target-class 如果设置true表示强转使用cglib代理<aop:aspect> aspect编程ref 用于确定切面类,从而确定通知--><aop:config><aop:aspect ref="myAspectId"><!-- 声明切入点,确定目标类上哪些方法将成为切入点,需要被增强 --><aop:pointcut expression="execution(* com.itheima.d_aspect.a_xml.*.*(..))" id="myPointcut"/><!-- 声明通知方式 1.前置通知<aop:before method=""/>method 切面类中具体的方法名称方法可以有一个参数,类型: org.aspectj.lang.JoinPoint用于获得当前执行方法的具体详情pointcut-ref 切入点的引用(大家共享)pointcut 给当前前置通知编写切入点表达式(自己使用)<aop:before method="myBefore" pointcut-ref="myPointcut"/>2.后置通知目标方法执行之后才执行,可以获得返回值。returning 用于设置通知第二个参数的名称,类型:Objectpublic void myAfterReturning(JoinPoint joinPoint,Object ret){<aop:after-returning returning="ret"/><aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut" returning="ret"/>3.环绕通知环绕通知方法要求1.返回类型Object2.必须抛出异常 throws Throwable3.必须接受一个参数,类型 ProceedingJoinPoint4.方法体中手动执行目标方法,Object obj = joinPoint.proceed();<aop:around method="myAround" pointcut-ref="myPointcut"/>4.抛出异常目标方法出现异常时执行,如果没有异常忽略。throwing 设置第二个参数名称,获得具体的异常信息的。类型:Throwablepublic void myAfterThrowing(JoinPoint joinPoint,Throwable e){<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>5.最终无论是否有异常,都将执行--><aop:after method="myAfter" pointcut-ref="myPointcut" /></aop:aspect></aop:config></beans>
* 切面类
/** * 切面类,存放所有通知,aspectj 没有提供接口,所有的通知都是通过配置文件确定。 */public class MyAspect {public void myBefore(JoinPoint joinPoint){System.out.println("前置通知 : " + joinPoint.getSignature().getName());}public void myAfterReturning(JoinPoint joinPoint,Object ret){System.out.println("后置通知 : " + ret );}public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{System.out.println("前");//手动执行目标类Object obj = joinPoint.proceed();System.out.println("后");return obj;}public void myAfterThrowing(JoinPoint joinPoint,Throwable e){System.out.println("抛出异常 : " + e.getMessage());}public void myAfter(JoinPoint joinPoint){System.out.println("最终");}}5.5 基于注解 aspectJ
* 步骤一:将切面类配置给spring
@Component
public class MyAspect {
* 步骤二:将切面类声明成切面
@Component
@Aspect
public class MyAspect {
* 步骤三:声明共有切入点
1.方法必须private,没有返回值,没有参数
2.之后使用将其当成方法调用。例如:@After("myPointcut()")
@Pointcut("execution(*com.itheima.d_aspect.b_annotation.*.*(..))")
privatevoid myPointcut(){}
* 步骤四:编写相应的通知
@Before 前置
@AfterReturning 后置,可以获得返回值,必须在注解中确定返回值参数名称。
@AfterThrowing 抛出异常,可以获得具体异常信息,必须在注解确定第二个参数名称
@Around 环绕
@After 最终
/** * 切面类,存放所有通知,aspectj 没有提供接口,所有的通知都是通过配置文件确定。 */@Component //2.<bean id="myAspectId" class="com.itheima.d_aspect.b_annotation.MyAspect"></bean>@Aspect//3.1 <aop:aspect ref="myAspectId"> 让切面类形成切面 (通知和切入点结合)public class MyAspect {//@Before("execution(* com.itheima.d_aspect.b_annotation.*.*(..))")// 取代 <aop:before method="myBefore" pointcut="execution(* com.itheima.d_aspect.b_annotation.*.*(..))"/>public void myBefore(JoinPoint joinPoint){System.out.println("前置通知 : " + joinPoint.getSignature().getName());}//@AfterReturning(value="execution(* com.itheima.d_aspect.b_annotation.*.*(..))",returning="ret")public void myAfterReturning(JoinPoint joinPoint,Object ret){System.out.println("后置通知 : " + ret );}//编写共有的切入点表达式@Pointcut("execution(* com.itheima.d_aspect.b_annotation.*.*(..))")private void myPointcut(){}//@Around("myPointcut()")public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{System.out.println("前");//手动执行目标类Object obj = joinPoint.proceed();System.out.println("后");return obj;}//@AfterThrowing(value="myPointcut()",throwing="e")public void myAfterThrowing(JoinPoint joinPoint,Throwable e){System.out.println("抛出异常 : " + e.getMessage());}@After("myPointcut()")public void myAfter(JoinPoint joinPoint){System.out.println("最终");}}
* 步骤五:必须在xml中扫描注解和启用aop自动代理
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 1 扫描 --><context:component-scan base-package="com.itheima.d_aspect.b_annotation"></context:component-scan><!-- 2 使aop注解生效 --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>6 JdbcTemplate
Spring支持持久模板
* spring提供 用于操作数据库模板。类似:DbUtils。使用时必须设置数据源(DataSource)
* 数据源:DBCP、C3P0等
* 导入jar包:
dbcp:
com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar
com.springsource.org.apache.commons.pool-1.5.3.jar
c3p0: com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
spring-jdbc spring-jdbc-3.2.0.RELEASE.jar
spring-tx(transaction) spring-tx-3.2.0.RELEASE.jar
数据库驱动:mysql-connector-java-5.1.22-bin.jar
6.1 创建数据库及表
create database spring_day02_db;use spring_day02_db;create table t_user( id int primary key auto_increment, username varchar(50), password varchar(32));insert into t_user(username,password) values('jack','1234');6.2 使用DBCP
回顾使用API连接
@Testpublic void demo01(){//1 创建数据库BasicDataSource dataSource = new BasicDataSource();// 1.1 驱动 dataSource.setDriverClassName("com.mysql.jdbc.Driver");// 1.2 urldataSource.setUrl("jdbc:mysql://localhost:3306/spring_day02_db");// 1.3 userdataSource.setUsername("root");// 1.4 passworddataSource.setPassword("1234");//2 创建模板JdbcTemplate jdbcTemplate = new JdbcTemplate();// 2.1 设置数据源jdbcTemplate.setDataSource(dataSource);//3 录入数据jdbcTemplate.update("insert into t_user(username,password) values(?,?)", "rose","1234");}}
* 配置数据源,配置模板,dao直接使用模板。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!--1 配置数据源 --><bean id="dataSourceId" class="org.apache.commons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/spring_day02_db"></property><property name="username" value="root"></property><property name="password" value="1234"></property></bean><!-- 2 配置模板,需要数据源 --><bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSourceId"></property></bean><!--3 配置dao,需要模板 --><bean id="userDaoId" class="com.itheima.e_jdbc.b_dbcp.UserDao"><property name="jdbcTemplate" ref="jdbcTemplateId"></property></bean>6.3 使用C3P0
* dao之后继承 JdbcDaoSupport,spring直接给dao注入数据源DataSource即可,JdbcDaoSupport底层自动进行模板创建。
c3p0配置
<!--1 配置数据源 c3p0 --><bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_day02_db"></property><property name="user" value="root"></property><property name="password" value="1234"></property></bean><!-- 2 配置模板,需要数据源 <bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSourceId"></property></bean>--><!--3 配置dao,需要模板 * 将数据源 datasource注入给dao,继承JdbcDaoSupport 提供setDataSource,且此方法中将自动的创建模板。--><bean id="userDaoId" class="com.itheima.e_jdbc.c_c3p0.UserDao"><property name="dataSource" ref="dataSourceId"></property></bean>
dao使用(继承JdbcDaoSupport)
public class UserDao extends JdbcDaoSupport{public void save(String username,String password){this.getJdbcTemplate().update("insert into t_user(username,password) values(?,?)", username,password);}public User find(int id) {// queryForObject 查询一个结果,如果没有结果抛异常。String sql = "select * from t_user where id = ?";return this.getJdbcTemplate().queryForObject(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class), id);}}6.4 使用properties
* 将连接数据的具体参数配合到properties文件,由spring加载properties,并在spring配置文件中使用。
jdbcinfo.properties
jdbc.driverClass=com.mysql.jdbc.Driverjdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring_day02_dbjdbc.user=rootjdbc.password=1234配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 0 加载properties文件 location 用于指定配置文件位置classpath: 固定的字符串表示从 src下获取在spring 配置文件中,就可以通过${key} 方式获取--><context:property-placeholder location="classpath:com/itheima/e_jdbc/d_properties/jdbcinfo.properties"/><!--1 配置数据源 c3p0 --><bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driverClass}"></property><property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property><property name="user" value="${jdbc.user}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 2 配置模板,需要数据源 <bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSourceId"></property></bean>--><!--3 配置dao,需要模板 * 将数据源 datasource注入给dao,继承JdbcDaoSupport 提供setDataSource,且此方法中将自动的创建模板。--><bean id="userDaoId" class="com.itheima.e_jdbc.d_properties.UserDao"><property name="dataSource" ref="dataSourceId"></property></bean></beans>6.5 JdbcTemplate API
* update进行 增删改操作
* queryForObject 查询一个
* query 查询所有
* queryForInt查询一个整形(分页)
public class UserDao extends JdbcDaoSupport{public void save(String username,String password){this.getJdbcTemplate().update("insert into t_user(username,password) values(?,?)", username,password);}public User find(int id) {// queryForObject 查询一个结果,如果没有结果抛异常。String sql = "select * from t_user where id = ?";return this.getJdbcTemplate().queryForObject(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class), id);}public List<User> findAll() {String sql = "select * from t_user";return this.getJdbcTemplate().query(sql, ParameterizedBeanPropertyRowMapper.newInstance(User.class));}}
框架 day37 Spring3,AOP,代理模式(动态/CGLIB/工厂bean),传统AOP,AspectJ框架(基于xml/注解),切入点表达式,jdbcTemplate
标签:
小编还为您整理了以下内容,可能对您也有帮助:
spring aop,aspectj aop的实现原理分别是什么,两种aop的框架都支持哪些增强方法
你好,别想的太难了,你可以参考一下底下:
1、使用基于注解的AOP事务管理
探索tx:annotation-driven标签:
标签是注解驱动的事务管理支持的核心。
标签的属性:
transaction-manager:指定到现有的PlatformTransactionManager bean的引用,通知会使用该引用。default="transactionManager"
mode:指定Spring事务管理框架创建通知bean的方式。可用的值有proxy和aspectj。前者是默认值,表示通知对象是个JDK代理;后者表示Spring AOP会使用AspectJ创建代理。
order:指定创建的切面的顺序。只要目标对象有多个通知就可以使用该属性。
proxy-target-class:该属性如果为true就表示你想要代理目标类而不是bean所实现的所有接口。default="false"
探索@Transactional注解:
你可以指定传播、隔离级别、超时以及允许和不允许的异常。
@Transactional注解的属性:
propagation:指定事务定义中使用的传播
isolation:设定事务的隔离级别
timeout:指定事务的超市(秒)
readOnly:指定事务的超时
noRollbackFor:目标方法可抛出的异常所构成的数组,但通知仍会提交事务
rollbackFor:异常所构成的数组,如果目标方法抛出了这些异常,通知就会回滚事务
基于注解的事务管理小结:
如果定义在类上,那么所有的方法都使用相同的方式,有些read就会抱怨给太多的东西了。
如果在每个方法上都定义注解,那么就会很麻烦。
(可以使用XML AOP事务管理能更好的处理这种情况)
2、使用XML AOP事务管理
标签,该标签会创建一个事务处理通知。
view plaincopy to clipboardprint?
或
<aop:pointcut id="allServiceMethods"
expression="execution(* com.apress.prospring2.ch16.services.*.*(..))"/>
<aop:advisor advice-ref="defaultTransactionAdvice"
pointcut-ref="allServiceMethods"/>
<tx:method
name="*"
isolation="DEFAULT"
propagation="REQUIRED"
no-rollback-for="java.lang.RuntimeException"
timeout="100"/>
<tx:method
name="get*"
read-only="true"/>
3、tx:advice标签简介
id是该advice bean的标识,而transaction-manager则必须引用一个PlatformTransactionManager bean。
还可以通过标签定制标签所创建的通知的行为。
标签的属性:
name:方法名的匹配模式,通知根据该模式寻找匹配的方法。
propagation:设定事务定义所用的传播级别。
isolation:设置事务的隔离级别。
timeout:指定事务的超时(秒)。
read-only:该属性为true指示事务是只读的
no-rollback-for:以逗号分隔的异常类的列表,目标方法可以跑出这些异常而不会导致通知执行回滚
rollback-for:以逗号分隔的异常类的列表,当目标方法跑出这些异常时会导致通知执行回滚。默认情况下,该列表为空,因此不在no-rollback-for列表中的任何运行时异常都会导致回滚。
中isolation(隔离)和propagation(传播)参数的含义:
getIsolationLevel:他对其他事务所看到的数据变化进行控制。
事务隔离级别:
隔离级别 说明
ISOLATION_DEFAULT 默认级别(对大多数数据库来说就是ISOLATION_READ_COMMITTED)
ISOLATION_READ_UNCOMMITTED 最低的隔离级别。事实上我们不应该隔离级别,因为在事务完成前,其他事务可以看到该事务所修改的数据。而在其他事务提交前,该事务也可以看到其他事务所做的修改。
ISOLATION_READ_COMMITTED 大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。遗憾的是,在该事务提交后,你就可以查看其他事务插入活更新的数据。这意味着在事务的不同点上,如果其他事务修改数据,你会看到不同的数据。
ISOLATION_REPEATABLE_READ 该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的数据集,即使其他事务修改了所查询的数据。然而如果其他事务插入了新数据,你就可以查询到该新插入的数据。
ISOLATION_SERIALIZABLE 代价最大、可靠性最高的隔离级别,所有的事务都是俺顺序一个接一个的执行。
getPropagationBehavior:指定了当代码请求一个新的事务时Spring所做的事情。
传播行为指:
传播行为 说明
PROPAGATION_REQUIRED 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务。
PROPAGATION_SUPPORTS 当前如果有事务,Spring就会使用该事务;否则不会开启一个新事务。
PROPAGATION_MANDATORY 当前如果有事务,Spring就会使用该事务;否则会抛出异常。
PROPAGATION_REQUIRES_NEW Spring总会开始一个新事务。如果当前有事务,则该事务挂起。
PROPAGATION_NOT_SUPPORTED Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当期有事务,则该事务挂起。
PROPAGATION_NEVER 即使当前有事务,Spring也会在飞事务环境下执行。如果当前有事务,则抛出异常。
PROPAGATION_NESTED 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与PROPAGATION_REQUIRED一样。
望采纳!
详解Spring AOP及事务配置三种模式
Spring AOP的设计思想,就是通过动态代理,在运行期对需要使用的业务逻辑方法进行增强。
使用场景如:日志打印、权限、事务控制等。
默认情况下,Spring会根据被代理的对象是否实现接口来选择使用JDK还是CGLIB。当被代理对象没有实现接口时,Spring会选择CGLIB。当实现了接口,Spring会选择JDK官方的代理技术,不过我们也可以通过配置的方式,让Spring强制使用CGLIB。
配置方式有两种:
2.1 XML模式
主要看下面的aop部分
xml相关切面配置
环绕通知可以实现上面的4种通知,并且可以控制业务方法是否执行。通过如下代码控制:
举例:
2.2 XML+注解模式
2.3 纯注解模式
只需要用注解@EnableAspectJAutoProxy替换掉
也分为3种模式
3.1 XML模式
3.2 基于XML+注解
3.3 纯注解
用@EnableTransactionManagement 注解替换掉
即可
书山有路勤为径,学海无涯苦作舟
spring的原理是什么?
一、 IoC(Inversion of control): 控制反转
1、IoC:
概念:控制权由对象本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系
核心:bean工厂;在Spring中,bean工厂创建的各个实例称作bean
二、AOP(Aspect-Oriented Programming): 面向方面编程 。
1、 代理的两种方式:
静态代理:
针对每个具体类分别编写代理类。
针对一个接口编写一个代理类。
动态代理:
针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类 。
2、 AOP的主要原理:动态代理 。
Spring工作原理
Spring 已经用过一段时间了,感觉Spring是个很不错的框架。内部最核心的就是IOC了,
动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射 ,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置 文件来动态的创建对象,和调用对象里的方法的 。
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是 在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些都是通过 配置类达到的。
Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明 管理的(Spring根据这些配置 内部通过反射去动态的组装对象)
要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。
Spring里用的最经典的一个设计模式就是:模板方法模式。
动态SpringAOP的是如何实现的?
SpringAOP是利用代理模式,在运行时生成一个目标对象的代理,并且使用代理代替目标对象,整个过程对使用者透明,使用者无法像使用目标对象一样使用代理对象,代理对象类型是目标对象所属类的子类或者接口实现,回龙观IT培训认为这个子类也是在运行时动态生成,这个生成子类的过程使用操作字节码技术,Spring框架中使用两种字节码技术:JDK动态代理和CGLIB,当目标类实现了接口时使用JDK动态代理,否则使用CGLIB代理。
AOP的实现包含下面几个步骤:
根据配置或注解解析切面。
生成AOP代理对象,给目标对象生成一个代理类以及代理类实例,根据解析出的切面,生成通知链设置到代理对象,在代理的回调中会执行通知链。
把AOP代理对象注册到容器中代替目标对象,当使用者向容器请求目标bean时,容器会返回代理对象。
下面对这几个步骤逐一的分析。
切面解析
在分析切面解析过程之前,首先先了解一下几个关键的接口,看下面的类图。
PointCut:描述切点,在进行切点匹配时,使用ClassFilter进行类匹配,MethodMatcher进行执行方法匹配。
Advice:通知,AfterAdvice后通知,BeforeAdvice前通知,DynamicIntroctionAdvice引用通知,环绕通知通过Interceptor实现。
Advisor:通知器,也就是切面,PointcutAdvisor切点通知器,IntroctionAdvisor引用通知器。
在创建AOP代理之前需要把相关的切面配置解析成上面类图中的接口子类的对象,对于ProxyFactoryBean来说,没有这个过程,因为这种方式下不能使用切点。
切面解析完成之后,把解析出的通知添加通知链中,AOP代理对象引用该通知链执行切面通知逻辑。对于aop标签方式和注解方式添加通知链这个动作的代码是类似的,解析切面这个过程有些差异。