springAOP面向切面编程
1:aop编程思想以及aop的实现
1:什么是aop
- 什么是oop
是:是将开发中遇到的客观现实的物件抽象成属性、方法并放入模板(类)中的一种编程思想
三大特生就是 封装 继承 多态 (他们都是基于抽象实现的)
- 什么是aop
是:是把纵向的oop的非核心的但是多个类中存在的重复的代码逻辑,抽取出来放到一个代理对象中的编程思想,例如每个类中都需要关闭io的操作,造成了代码大量的冗余,我很横向的抽取出来放到一个代理对象中,用的时候切入引用就可以了
只负责核心代码,抽取出来的代码用代理对象处理非核心但是需要的代码功能
2:aop思想的设计的7个核心概念
- 连接点 连接点(Joinpoint):每个目标代理的方法
- 切入点(pointcut) 一个类中有多个连接点,这些连接点被称为切点
- 增强(advice) 就是不改类内容的情况下对类功能的补充
- 目标对象(target) 目标代理的对象
- 织入 (weaving)就是蒋增强添加到目标
- 代理(proxy) 增强了的对象
- 切面 切点切入后,加上代理就形成了切面
3:spring aop 实现原理
所说的aop面向切面编程,也就是将核心关注点意外的可以复用的提取出来,通过
aop技术,在程序运行起来时候动态的增强的代码切入到目标中,在这个过程中会产生一个代理对象,
代理对象有着原来方法和能力的,而且增加了新功能
1:静态代理
静态代理:
装饰者模式 连接池的连接,
Connection.close();
在不改变原有代码情况下,直接使用装饰者模式生成一个新的对象!
动态代理:
在代码运行起来时,动态的修改原有类的方法内容,不需要预先设计好代理类
装饰者模式:
2:JDK代理
在代码运行起来时候,动态的生成增强的代码,不需要预先创建好代理类
JDK:类似于静态代码的方式!只不过会动态的生成一个代理类!再生成代理对象!
要求目标类必须实现了’接口’!具体实现:
要求有接口
有接口实现类 实现接口的方法
测试代理:
public class JDKproxy { @Test public void testProxy(){ //创建目标对象 Student student = new StudentImpl(); //创建代理对象 传入目标代理的参数类加载器 类接口 内部类 Student student1 = (Student) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler() { /** * * @param proxy 代理对象 * @param method 目标方法 * @param args 目标方法参数 * @return 代理对象方法的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //之前添加 System.out.println("添加增强功能前"); Object invoke = method.invoke(student, args); //之后 System.out.println("添加目标执行后"); return invoke; } }); //调用代理对象 student1.eat(); } }
3:CGlib代理
cglib一种动态拦截方法生成的技术!他不会额外生成类!在代码编译的时候动态改变原来类的字节码文件!
生成代理对象! student --> student --> 增强 --> 代理对象!cglib不要求目标类必须实现接口!
1://创建代理类
public class Student { public void run(){ System.out.println("Student.run"); } }
2:创建增强类增强方法
public class MyAdvice { public void before(){ System.out.println("MyAdvice.before"); } public void after(){ System.out.println("MyAdvice.after"); } }
3:创建拦截
public class MyInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //创建增强 MyAdvice myAdvice = new MyAdvice(); myAdvice.before(); //目标 Object o1 = methodProxy.invokeSuper(o, objects); myAdvice.after(); return o1; } }
测试
public class CglibTest { @Test public void testCglib(){ //创建拦截 MyInterceptor myInterceptor = new MyInterceptor(); Enhancer enhancer = new Enhancer(); enhancer.setCallback(myInterceptor); enhancer.setSuperclass(Student.class); Student student = (Student) enhancer.create(); student.run(); } }
spring aop会自动根据情况进行底层实现的切换! 优先是jdk动态代理!如果没有接口只需要向项目中导入
cglib依赖会自动切换!对比JDK CGLIB
jdk是jdk内置的代理,不需要导入第三方依赖,jdk要求有共同接口的存在,用增强对象执行方法,动态添加增强功能
cglib不需要接口,但是需要一个拦截器,在拦截器里面执行目标方法,执行前后添加增强方法
4: aop基于xml配置
第一步:导入依赖
spring-aop
spring-aspect
aopalliance
aspectjweaver第二步:目标类
service类
第三步:写增强
每个增强方法(除了环绕)中都有一个Jionpoint参数,为了获取目标代理方法的一些信息,另外afterReturning方法中有一个Throwable参数,为了获取异常的信息,在添加注解时要注意添加方式
环绕通知:返回值Object,返回执行的目标方法
参数proceeding JionPoint
afterThrowing(JoinPoint joinPoint,Throwable throwable)方法
/** * Throwable throwable 只能作为错误通知传递! * joinPoint 除了环绕都可以传递 * @param joinPoint 连接点,除了环绕其他方法都有连接点 * @param throwable 给你一个对象 让你获取错误信息 */ //import org.aspectj.lang.JoinPoint; public void returnException(JoinPoint joinPoint,Throwable throwable){ //记住 环绕通知是切点!其他的通知都有连接点!可以写 可以不写! //写是为方便获取目标类和方法的信息 String name = joinPoint.getSignature().getName(); String name1 = joinPoint.getTarget().getClass().getName(); String message = throwable.getMessage(); System.out.println("发送邮件"); System.out.println("类:"+name1+" 方法:"+name+" 错误内容:"+message); }
第四部:写配置
<!--第一步:扫描包--> <context:component-scan base-package="com.it.dao.impl,com.it.service.impl, com.it.controller,com.it.advice"></context:component-scan> <!--第二步:切点配置--> <!--开启种事务--> <aop:config> <aop:pointcut id="pc" expression="execution(* com..service.impl.*Impl.*(..))"> </aop:pointcut> <aop:aspect ref="accountAdvice"> <aop:before method="before" pointcut-ref="pc"> </aop:before> <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning> <aop:after-throwing method="afterThrowing" pointcut-ref="pc"></aop:after-throwing> <aop:after method="after" pointcut-ref="pc"> </aop:after> </aop:aspect> </aop:config>
第五步:测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml")//测试环境 public class AccountTest { @Autowired private AccountController accountController; @Test public void testAccount(){ accountController.transfer("zhangsan", "lisi", 5000); } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gUkfZoN-1572167116111)(C:\Users\32302\Desktop\typora\img\测试.PNG)]
5:aop基于注解的配置
步骤1:导包
步骤2:目标类
步骤3:增强类1: 在增强类上面ioc容器管理 @Component 切面的注解 @Aspect 2:配置切点方法 @Pointcut("execution(表达式)") public void xxx(){} 避免后面重复写表达式切点! 3:方法上配置对应的切点 @Before(切点表达式 1.直接execution(表达式)
2.可以引用声明的切点 “类名.切点方法()”);
@After();
@Around();
@AfterReturning();
@AfterThrowing(pointcut=,throwing=“异常参数名称”)4:开启注解形式aop的支持 配置文件中 <aop:aspectj-autoproxy />
6: aop练习
转账业务:
。。。
spring数据库数据库相关 事务
1. 回顾什么是数据库事务
数据库事务是数据库执行的逻辑单位,为了保证数据额安全性,我们要保证这个逻辑单位的完全失败执行或者
完全成功执行 #### 2. 数据库的acid 特性 a:原子性 c:持久性 i:隔离性 d:一致性 #### 3. 事物的隔离性 四个隔离级别 read uncommited read commieted repeat read serializable #### 4. 不同级别的隔离会导致什么问题 #### 5. spring数据库事务的实现和涉及的包
spring 事务的实现 一个增强 一个事务管理接口 三个事务管理器的实现类 ##### spring-jdbc: DatasourceTrasactionManager 实现的持久层技术 JdbcTemplate Dbutils 原生的jdbc myBatis 都操作connection ##### spring-tx: 事物的增强 事务管理的接口 PlateFormTrasactionManager ##### spring-orm(整合第三方的orm类型的持久层框架) JpaTrasactionManager HibernateTrasactionManager
2. spring 事务步骤 -----xml
步骤一:导包
事务:spring-tx
代理:cglib
spring-aop,spring-aspects,aopalliance,aspectjweaver
用到spring四个核心依赖
spring -aop
数据库:MySQL c3p0 spring-jdbc
步骤二:java核心代码(转账过程能运行起来)
步骤三:编写增强
@Component public class AccountAdvice { public void before(JoinPoint joinPoint){ //开启事务 System.out.println("开启事务"); } public void afterReturning(){ //事务成功,提交事务 System.out.println("提交"); } public void afterThrowing(JoinPoint joinPoint,Throwable throwable){ //有异常回滚 System.out.println("回滚"); } public void after(){ //关闭 System.out.println("关闭"); } //环绕 public Object round(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("前"); Account proceed = (Account) joinPoint.proceed();//目标方法 System.out.println("后"); return proceed; } }
步骤四编写xml
<!--扫描--> <context:component-scan base-package="com.it.dao.impl,com.it.service.impl, com.it.controller,com.it.advice"></context:component-scan> <!--c3p0--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"></bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启种事务--> <aop:config> <aop:pointcut id="pc" expression="execution(* com..service.impl.*Impl.*(..))"></aop:pointcut> <aop:aspect ref="accountAdvice"> <aop:before method="before" pointcut-ref="pc"></aop:before> <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning> <aop:after-throwing method="afterThrowing" pointcut-ref="pc" throwing="throwable"></aop:after-throwing> <aop:after method="after" pointcut-ref="pc"></aop:after> </aop:aspect> </aop:config>
运行结果如上图
3: spring事务管理使用步骤 annotation
<!--扫描--> <context:component-scan base-package="com.it.dao.impl,com.it.service.impl, com.it.controller,com.it.advice"></context:component-scan> <!--c3p0 并持久层注入jdbcTemplate--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"></bean> <!--jdbcTemplate中传入c3p0--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!--注解申明--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
增强类:
@Component @Aspect public class AccountAdvice { //切点方法 @Pointcut("execution(* com..service.impl.*Impl.*(..))") public void asp(){ } @Before("AccountAdvice.asp()") public void before(JoinPoint joinPoint){ //开启事务 System.out.println("开启事务"); } @AfterReturning("AccountAdvice.asp()") public void afterReturning(){ //事务成功,提交事务 System.out.println("提交"); } @AfterThrowing(value = "AccountAdvice.asp()",throwing = "throwable") public void afterThrowing(JoinPoint joinPoint,Throwable throwable){ //有异常回滚 System.out.println("回滚"); } @After("AccountAdvice.asp()") public void after(){ //关闭 System.out.println("关闭"); } //环绕 @Around("AccountAdvice.asp()") public Object round(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("前"); Account proceed = (Account) joinPoint.proceed();//目标方法 System.out.println("后"); return proceed; } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KvELJrYq-1572167116113)(C:\Users\32302\Desktop\typora\img\注解.PNG)]
步骤一:在目标方法或者目标类上使用注解申明
@Transactional
@Transactional(isolation=Isolation.READ_COMMITED,propatation=Propatation.SUPORTS,readOnly=true,timeOut=30)
作用位置:类或者方法上
注意:如果添加在类上,类中所有方法均被开启事务,如果只添加在方法上面,则
支队本方法生效,如果类上和方法上都有添加则在方法杀不过面的有效
属性中少了name属性,因为直接作用在具体位置上面的。
编写配置文件
<!--步骤一根据持久层框架选择事务管理器的实现类--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--步骤二:配置自配的增强--> <tx:advice id="advice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="find*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="select*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="query*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="modify*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="transfer*" read-only="true" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="drop*" read-only="false" timeout="30" propagation="REQUIRED" isolation="READ_COMMITTED"/> <tx:method name="*" ></tx:method> </tx:attributes> </tx:advice> <!--步骤三:配置aopconfig--> <aop:config> <aop:pointcut id="pc" expression="execution(* com..service.impl.*Impl.*(..))"></aop:pointcut> <aop:advisor advice-ref="advice" pointcut-ref="pc"></aop:advisor> </aop:config>
解释:expression="execution(* com…service.impl.Impl.(…))
第一个* 代表所代理的目标方法访问类型是任意类型,
两个…代表忽略中间包的任意数量层级,
第二个代表一Impl结尾的类,
括号前面的代表任意方法
括号中的两个点代表任意数量类型的方法参数