ssm框架复习巩固
SSM框架复习第六天:动态代理 AOP(面向切面编程)
1.动态代理:动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码.
简单点解释,比方说你想在你的biz层所有类中都加上一个打印‘你好’的功能,这时就可以用aop思想来做.你先写个类写个类方法,方法经实现打印‘你好’,然后Ioc这个类 ref=“biz.*”让每个类都注入即可实现。
AOP底层的实现原理:使用动态代理增强对象
spring 实现AOP的时候底层的代理方式
1. jdk动态代理
2. CGLib动态代理
不同:
JDK:
1.目标类必须实现接口 JDK的动态代理是针对接口产生代理对象
2.目标类和代理类之间是(同级)兄弟关系,都会实现相同的接口
Cglib:
1.目标类不需要实现接口也能产生代理对象,cglib的动态代理是针对目标类产生代理对象
2.目标类和代理类之间是一种继承关系
2.AOP
AOP的概念
AOP(面向切面编程)
OOP(面向对象编程)
OOP : 专注于在业务开发过程中把各个抽象的东西封装成对象 (属性 行为)
AOP : 切面 面向对象编程的一种延续
AOP:是一种编程思想,和oop一样,可以说是oop的一种延伸。在传统编程写代码的时候,如果我们在在多个类中调用(当我们需要为分散的对象引入公共行为的时候)同一个方法(功能)的时候,可以能回导致重复的代码太多了,方法与方法(业务逻辑)之间存在严重耦合(例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。)这个时候我们要把这个方法(功能)封装成一个封面,然后注入要所需要这个功能的类中。(利用spring的ioc的rel属性)将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。
AOP解决什么问题
AOP专注于把各个业务逻辑部分进行抽取,达到减低各个业务逻辑部分之间耦合度的目的
两个方法产生了关联(联系)
方法与方法之间的耦合 一个方法(业务)的改变会影响另一个方法的改变
就是解决方法(业务逻辑)与方法(业务逻辑)的耦合
传统代码开发存在的问题
1. 重复代码太多
2. 方法与方法(业务逻辑与业务逻辑)之间存在耦合
3.Spring的AOP的开发
1. xml配置
1.导入依赖
<groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
2.在业务层创建接口和实现类
package com.swlz.service; /** * 定义了对用户进行增删改查的方法 */ public interface IUserService { public void findAll(); public void saveUser(String user); public void updateUser(); public void deleteUser(); }
package com.swlz.service.impl; import com.swlz.service.IUserService; /** * 用户基本增删改查的业务代码 */ public class UserServiceImpl implements IUserService { public void findAll() { System.out.println("UserServiceImpl 调用Dao查询所有用户"); } public void saveUser(String user) { System.out.println("UserServiceImpl 调用Dao保存用户" + user); } public void updateUser() { System.out.println("UserServiceImpl 调用Dao更新用户"); } public void deleteUser() { System.out.println("UserServiceImpl 调用Dao删除用户"); } }
3.创建日志类(增强的方法)
public class LogUtils {
public void printLog(){
System.out.println("记录日志.....////");
}
// 方法执行之前
public void beforeLog(){
System.out.println("记录日志 ...beforeLog");
}
// 方法执行之后
public void afterReturingLog(){
System.out.println("记录日志 ...afterReturingLog");
}
// 方法出现异常的时候
public void afterThrowingLog(){
System.out.println("记录日志 ...afterThrowingLog");
}
// 所有方法执行完之后,也就是最终
public void afterLog(){
System.out.println("记录日志 ...afterLog");
}
}
4.在xml配置文件中配置
<?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"> <bean id="userService" class="com.swlz.service.impl.UserServiceImpl"></bean> <bean id="accountService" class="com.swlz.service.impl.AccountServiceImpl"></bean> <!--Spring Aop 配置--> <!--第一步 配置通知类对象 --> <bean id="logAdvice" class="com.swlz.log.LogUtils"></bean> <!--配置aop--> <!--第二步 开启AOP配置(完成自动代理)--> <aop:config> <!-- 切点表达式 id="pc"--> <aop:pointcut id="pc" expression="execution(* com.swlz.service..*(..))"></aop:pointcut> <!--配置切面--> <aop:aspect ref="logAdvice"> <!--定义通知和通知中指定切点 切点定义方式(AspectJ框架提供):通过切点表达式--> <!-- <aop:before method="printLog" pointcut="execution(public void com.swlz.service.impl.UserServiceImpl.findAll())"></aop:before>--> <!--切点定义方式(AspectJ框架提供):通过切点表达式 1. 完整写法 public void com.bianyiit.service.impl.UserServiceImpl.saveUser(String) 方法访问修饰符 返回值 包名 类名 方法名 方法参数 2. 方法访问修饰符可以被省略 void com.bianyiit.service.impl.UserServiceImpl.saveUser(String) 返回值 包名 类名 方法名 方法参数 3 . 方法返回值类型可以用 * 号代替 * com.bianyiit.service.impl.UserServiceImpl.saveUser(String) 返回值 包名 类名 方法名 方法参数 4 . 包名和类名可以省略 * save*(..)) 返回值 方法名 方法参数 5 . 整个表达式中只有 方法返回值类型 方法名 方法参数不能省略,其他都能省略 其中 方法返回类型 和方法名可以使用*号通配, 方法参数可以使用..通配 方法名 save* 以save开头的方法 * *(..)) 返回值 方法名 方法参数 --> <!-- <aop:before method="printLog" pointcut="execution(* save*(..))"></aop:before>--> <!-- pointcut="execution(* com.swlz.service..*(..)) 切点表达式 表示service层中的所有类中所有的方法--> <aop:before method="printLog" pointcut-ref="pc"></aop:before> <!-- <aop:before method="beforeLog" pointcut-ref="pc"/> <-方法执行之后 --> <aop:after-returning method="afterReturingLog" pointcut-ref="pc"></aop:after-returning> <!-- <-方法出现异常的时候所要执行的方法 –>--> <aop:after-throwing method="afterThrowingLog" pointcut-ref="pc"></aop:after-throwing> <!-- <-所有方法执行完之后,也就是最终–>--> <aop:after method="afterLog" pointcut-ref="pc"></aop:after> </aop:aspect> </aop:config> </beans>
4.四张基本通知(具体增强的功能(方法))类型基于xml配置的时候基本的执行顺序
前置通知--目标方法---后置通知----最终通知
前置通知--目标方法---异常通知----最终通知
注意:如果出现了异常就不会执行后置通知
切面:切点+通知
切点:需要对目标中那些方法进行增强的定义
advice(通知):具体增强的功能(方法)
连接点(joinPoint):所有有可能被增强的方法
今日学习感受:唯有坚持才会不负你所热爱的,有些东西需要你自己正在的去尝试并且坚持下去,它会在无形中可能会给你带来意外的惊喜。最后一句话:我心光明,心向光明,心之所向,必能所往!
浙公网安备 33010602011771号