网站跳出率是什么意思,h5免费制作平台哪个好,新七建设集团有限公司网站,大连中小网站建设公司目录
1 AOP实现步骤#xff08;以前打印当前系统的时间为例#xff09;
2 AOP工作流程
3 AOP核心概念
4 AOP配置管理
4-1 AOP切入点表达式
4-1-1 语法格式
4-1-2 通配符
4-2 AOP通知类型
五种通知类型
AOP通知获取数据
获取参数
获取返回值
获取异常
总结
5 …目录
1 AOP实现步骤以前打印当前系统的时间为例
2 AOP工作流程
3 AOP核心概念
4 AOP配置管理
4-1 AOP切入点表达式
4-1-1 语法格式
4-1-2 通配符
4-2 AOP通知类型
五种通知类型
AOP通知获取数据
获取参数
获取返回值
获取异常
总结
5 AOP事务管理
5.1 Spring事务简介
5.2 步骤
Transactional
5.3 Spring事务角色
5.4 Spring事务属性
5.4.1 事务配置
5.4.2 事务传播行为 AOP是在不改原有代码的前提下对其进行增强。
1 AOP实现步骤以前打印当前系统的时间为例
1添加依赖
dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version
/dependency
因为spring-context中已经导入了spring-aop ,所以不需要再单独导入spring-aop
导入AspectJ的jar包,AspectJ是AOP思想的一个具体实现Spring有自己的AOP实现但是相比于AspectJ来说比较麻烦所以我们直接采用Spring整合ApsectJ的方式进行AOP开发。
2定义接口与实现类
3定义通知类和通知
通知就是将共性功能抽取出来后形成的方法共性功能指的就是当前系统时间的打印。
public class MyAdvice {public void method(){System.out.println(System.currentTimeMillis());}
}4定义切入点
明确要增强什么方法 这里是update()
public class MyAdvice {Pointcut(execution(void com.itheima.dao.BookDao.update()))private void pt(){}public void method(){System.out.println(System.currentTimeMillis());}
}
5制作切面
切面是用来描述通知和切入点之间的关系关系绑定
public class MyAdvice {Pointcut(execution(void com.itheima.dao.BookDao.update()))private void pt(){}Before(pt())public void method(){System.out.println(System.currentTimeMillis());}
}Before翻译过来是之前也就是说通知会在切入点方法执行之前执行
6将通知类配给容器并表示为切面类
Component
Aspect
public class MyAdvice {Pointcut(execution(void com.itheima.dao.BookDao.update()))private void pt(){}Before(pt())public void method(){System.out.println(System.currentTimeMillis());}
}
7开启注解格式AOP功能
Configuration
ComponentScan(com.itheima)
EnableAspectJAutoProxy
public class SpringConfig {
}2 AOP工作流程 1Spring容器启动
容器启动就需要去加载bean以下是需要被加载的类
需要被增强的类如:BookServiceImpl 通知类如:MyAdvice
注意此时bean对象还没有创建成功 2读取所有切面配置中的切入点 3初始化bean
判定bean对应的类中的方法是否匹配到任意切入点 匹配失败创建原始对象,如UserDao
匹配失败说明不需要增强直接调用原始对象的方法即可。
匹配成功创建原始对象目标对象的代理对象,如: BookDao
匹配成功说明需要对其进行增强
对哪个类做增强这个类对应的对象就叫做目标对象
因为要对目标对象进行功能增强而采用的技术是动态代理所以会为其创建一个代理对象
最终运行的是代理对象的方法在该方法中会对原始方法进行功能增强 4获取bean执行方法
获取的bean是原始对象时调用方法并执行完成操作
获取的bean是代理对象时根据代理对象的运行模式运行原始方法与增强的内容完成操作
如果目标对象中的方法会被增强那么容器中将存入的是目标对象的代理对象。
如果目标对象中的方法不被增强那么容器中将存入的是目标对象本身。
3 AOP核心概念 两个核心概念
目标对象(Target)原始功能去掉共性功能对应的类产生的对象这种对象是无法直接完成最终工作的
代理(Proxy)目标对象无法直接完成工作需要对其进行功能回填通过原始对象的代理对象实 现
简单来说
目标对象就是要增强的类对应的对象也叫原始对象不能说它不能运行只能说它在运行的过程中对于要增强的内容是缺失的。
SpringAOP是在不改变原有设计(代码)的前提下对其进行增强的它的底层采用的是代理模式实现 的所以要对原始对象进行增强就需要对原始对象创建代理对象在代理对象中的方法把通知 内容加进去就实现了增强,这就是我们所说的代理(Proxy)。
SpringAOP的本质或者可以说底层实现是通过代理模式。
4 AOP配置管理
4-1 AOP切入点表达式
切入点:要进行增强的方法
切入点表达式:要进行增强的方法的描述方式
4-1-1 语法格式
描述方式一执行com.itheima.dao包下的BookDao接口中的无参数update方法
execution(void com.itheima.dao.BookDao.update())
描述方式二执行com.itheima.dao.impl包下的BookDaoImpl类中的无参数update方法
execution(void com.itheima.dao.impl.BookDaoImpl.update())
切入点表达式标准格式动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常 名
execution(public User com.itheima.service.UserService.findById(int))execution动作关键字描述切入点的行为动作例如execution表示执行到指定切入点
public:访问修饰符,还可以是publicprivate等可以省略
User返回值写返回值类型
com.itheima.service包名多级包使用点连接
UserService:类/接口名称 findById方法名 int:参数直接写参数的类型多个类型用逗号隔开
异常名方法定义中抛出指定异常可以省略
4-1-2 通配符
execution(void com.itheima.dao.BookDao.update())
匹配接口能匹配到
execution(void com.itheima.dao.impl.BookDaoImpl.update())
匹配实现类能匹配到
execution(* com.itheima.dao.impl.BookDaoImpl.update())
返回值任意能匹配到
execution(* com.itheima.dao.impl.BookDaoImpl.update(*))
返回值任意但是update方法必须要有一个参数无法匹配要想匹配需要在update接口和实现类添加
参数
execution(void com.*.*.*.*.update())
返回值为void,com包下的任意包三层包下的任意类的update方法匹配到的是实现类能匹配
execution(void com.*.*.*.update())
返回值为void,com包下的任意两层包下的任意类的update方法匹配到的是接口能匹配
execution(void *..update())
返回值为void方法名是update的任意包下的任意类能匹配
execution(* *..*(..))
匹配项目中任意类的任意方法能匹配但是不建议使用这种方式影响范围广
execution(* *..u*(..))
匹配项目中任意包任意类下只要以u开头的方法update方法能满足能匹配
execution(* *..*e(..))
匹配项目中任意包任意类下只要以e结尾的方法update和save方法能满足能匹配
execution(void com..*())
返回值为voidcom包下的任意包任意类任意方法能匹配*代表的是方法
execution(* com.itheima.*.*Service.find*(..))
将项目中所有业务层方法的以find开头的方法匹配
execution(* com.itheima.*.*Service.save*(..))
将项目中所有业务层方法的以save开头的方法匹配后面两种更符合我们平常切入点表达式的编写规则
描述切入点通常描述接口而不描述实现类
4-2 AOP通知类型
五种通知类型
前置通知、后置通知、环绕通知(重点)、返回后通知(了解)、抛出异常后通知(了解) (1)前置通知追加功能到方法执行前,类似于在代码1或者代码2添加内容
(2)后置通知,追加功能到方法执行后,不管方法执行的过程中有没有抛出异常都会执行类似于在代 码5添加内容
(3)返回后通知,追加功能到方法执行后只有方法正常执行结束后才进行,类似于在代码3添加内容 如果方法执行抛出异常返回后通知将不会被添加
(4)抛出异常后通知,追加功能到方法抛出异常后只有方法执行出异常才进行,类似于在代码4添加内 容只有方法抛出异常后才会被添加
(5)环绕通知,环绕通知功能比较强大它可以追加功能到方法执行的前后这也是比较常用的方式 它可以实现其他四种通知类型的功能
环绕通知
环绕通知需要在原始方法的前后进行增强所以环绕通知就必须要能对原始操作进行调用
对于切入点没有返回值的处理
Component
Aspect
public class MyAdvice {Pointcut(execution(void com.itheima.dao.BookDao.update()))private void pt(){}Pointcut(execution(int com.itheima.dao.BookDao.select()))private void pt2(){}Around(pt2())public void aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println(around before advice ...);//表示对原始操作的调用pjp.proceed();System.out.println(around after advice ...);}
}对于切入点有返回值的处理
Component
Aspect
public class MyAdvice {Pointcut(execution(void com.itheima.dao.BookDao.update()))private void pt(){}Pointcut(execution(int com.itheima.dao.BookDao.select()))private void pt2(){}Around(pt2())public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println(around before advice ...);//表示对原始操作的调用Object ret pjp.proceed();System.out.println(around after advice ...);return ret;}
} 环绕通知注意事项
1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用进而实现原始方法 调用前后同时添加通知
2. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
3. 对原始方法的调用可以不接收返回值通知方法设置成void即可如果接收返回值最好设定为 Object类型
4. 原始方法的返回值如果是void类型通知方法的返回值类型可以设置成void,也可以设置成 Object
5. 由于无法预知原始方法运行后是否会抛出异常因此环绕通知方法必须要处理Throwable异常
AOP通知获取数据
获取切入点方法的参数所有的通知类型都可以获取参数
JoinPoint适用于前置、后置、返回后、抛出异常后通知
ProceedingJoinPoint适用于环绕通知
获取参数
非环绕通知获取方式
在方法上添加JoinPoint,通过JoinPoint来获取参数
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}Before(pt())public void before(JoinPoint jp) Object[] args jp.getArgs();System.out.println(Arrays.toString(args));System.out.println(before advice ... );}//...其他的略
}环绕通知获取方式
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}Around(pt())public Object around(ProceedingJoinPoint pjp)throws Throwable {Object[] args pjp.getArgs();System.out.println(Arrays.toString(args));Object ret pjp.proceed();return ret;}//其他的略
}
注意
pjp.proceed()方法是有两个构造方法一个有参数一个没参数
调用无参数的proceed当原始方法有参数会在调用的过程中自动传入参数
所以调用这两个方法的任意一个都可以完成功能
但是当需要修改原始方法的参数时就只能采用带有参数的方法,如下:
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}Around(pt())public Object around(ProceedingJoinPoint pjp) throws Throwable{Object[] args pjp.getArgs();System.out.println(Arrays.toString(args));args[0] 666;Object ret pjp.proceed(args);return ret;}//其他的略
}有了这个特性后我们就可以在环绕通知中对原始方法的参数进行拦截过滤避免由于参数的 问题导致程序无法正确运行保证代码的健壮性。
获取返回值
对于返回值只有返回后AfterReturing和环绕Around这两个通知类型可以获取
环绕通知获取返回值
上述代码中ret就是方法的返回值我们是可以直接获取不但可以获取如果需要还可以进行修改。
返回后通知获取返回值
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}AfterReturning(value pt(),returning ret)public void afterReturning(Object ret) {System.out.println(afterReturning advice ...ret);}//其他的略
}注意 获取异常
对于获取抛出的异常只有抛出异常后AfterThrowing和环绕Around这两个通知类型可以获取
环绕通知获取异常
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}Around(pt())public Object around(ProceedingJoinPoint pjp){Object[] args pjp.getArgs();System.out.println(Arrays.toString(args));args[0] 666;Object ret null;try{ret pjp.proceed(args);}catch(Throwable throwable){t.printStackTrace();}return ret;}//其他的略
}抛出异常后通知获取异常
Component
Aspect
public class MyAdvice {Pointcut(execution(* com.itheima.dao.BookDao.findName(..)))private void pt(){}AfterThrowing(value pt(),throwing t)public void afterThrowing(Throwable t) {System.out.println(afterThrowing advice ...t);}//其他的略
}总结
核心概念
代理ProxySpringAOP的核心本质是采用代理模式实现的
连接点JoinPoint在SpringAOP中理解为任意方法的执行
切入点Pointcut匹配连接点的式子也是具有共性功能的方法描述
通知Advice若干个方法的共性功能在切入点处执行最终体现为一个方法
切面Aspect描述通知与切入点的对应关系
目标对象Target被代理的原始对象成为目标对象
*匹配任意符号常用
.. 匹配多个连续的任意符号常用
通知中获取参数
-获取切入点方法的参数所有的通知类型都可以获取参数
JoinPoint适用于前置、后置、返回后、抛出异常后通知
ProceedingJoinPoint适用于环绕通知
-获取切入点方法返回值前置和抛出异常后通知是没有返回值后置通知可有可无所以不做研究
返回后通知
环绕通知
-获取切入点方法运行异常信息前置和返回后通知是不会有后置通知可有可无所以不做研究
抛出异常后通知
环绕通知
5 AOP事务管理
5.1 Spring事务简介
事务作用在数据层保障一系列的数据库操作同成功同失败
Spring事务作用在数据层或业务层保障一系列的数据库操作同成功同失败
5.2 步骤
1在需要被事务管理的方法上添加注解
public interface AccountService {/*** 转账操作* param out 传出方* param in 转入方* param money 金额*///配置当前接口方法具有事务public void transfer(String out,String in ,Double money) ;
}Service
public class AccountServiceImpl implements AccountService {Autowiredprivate AccountDao accountDao;Transactionalpublic void transfer(String out,String in ,Double money) {accountDao.outMoney(out,money);int i 1/0;accountDao.inMoney(in,money);}}Transactional
Transactional可以写在接口类上、接口方法上、实现类上和实现类方法上
写在接口类上该接口的所有实现类的所有方法都会有事务
写在接口方法上该接口的所有实现类的该方法都会有事务
写在实现类上该类中的所有方法都会有事务
写在实现类方法上该方法上有事务
建议写在实现类或实现类的方法上 2在JdbcConfig类中配置事务管理器
public class JdbcConfig {Value(${jdbc.driver})private String driver;Value(${jdbc.url})private String url;Value(${jdbc.username})private String userName;Value(${jdbc.password})private String password;Beanpublic DataSource dataSource(){DruidDataSource ds new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}//配置事务管理器mybatis使用的是jdbc事务Beanpublic PlatformTransactionManager transactionManager(DataSource
dataSource){DataSourceTransactionManager transactionManager new
DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}
}3 开启事务注解
在SpringConfig的配置类中开启
Configuration
ComponentScan(com.itheima)
PropertySource(classpath:jdbc.properties)
Import({JdbcConfig.class,MybatisConfig.class
//开启注解式事务驱动
EnableTransactionManagement
public class SpringConfig {
}转换的业务出现错误后事务就可以控制回顾保证数据的正确性。
5.3 Spring事务角色 事务管理员发起事务方在Spring中通常指代业务层开启事务的方法
事务协调员加入事务方在Spring中通常指代数据层方法也可以是业务层方法
5.4 Spring事务属性
5.4.1 事务配置 上面这些属性都可以在Transactional注解的参数上进行设置。
readOnlytrue只读事务false读写事务增删改要设为false,查询设为true。
timeout:设置超时时间单位秒在多长时间之内事务没有提交成功就自动回滚-1表示不设置超 时时间。
rollbackFor:当出现指定异常进行事务回滚。
noRollbackFor:当出现指定异常不进行事务回滚
注意
Spring的事务只会对Error异常和RuntimeException异常及其子类进行事务回顾其他的异常类型是不会回滚的对应IOException不符合上述条件所以不回滚
5.4.2 事务传播行为
实际案例
记录转账流程日志 如果转出成功但是转入失败 那么事务都会回滚 日志操作也不会执行
这个时候我们就想能不能让log方法单独是一个事务呢要想解决这个问题就需要用到事务传播行为
事务传播行为事务协调员对事务管理员所携带事务的处理态度。
具体如何解决需要用到propagation属性。
1修改logService改变事务的传播行为
Service
public class LogServiceImpl implements LogService {Autowiredprivate LogDao logDao;//propagation设置事务属性传播行为设置为当前操作需要新事务Transactional(propagation Propagation.REQUIRES_NEW)public void log(String out,String in,Double money ) {logDao.log(转账操作由out到in,金额money);}
}这样不管转账是否成功都会记录日志。
2事务传播行为的可选值