Spring框架学习总结二
前言
已经快一个月没有更新博客了,这一个月的事情有点多,并且我部署到github上的博客被墙了,现在重新部署到了云服务器上。接下来就继续Spring框架的总结。
AOP编程
aop 为Aspect Oriented Programming的缩写,意为面向切面编程。意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。aop编程的优点在于,不更改源码的情况下,aop可以进行权限的验证,日志记录,性能检测,事务控制。
Spring底层的AOP原理
- 动态代理
- JDK动态代理: 面向接口的,只能对实现了接口的类产生代理。
- Cglib动态代理:对没有实现接口的类产生代理对象(生成子类对象)
- 类实现了接口,Spring就用JDK动态代理,没有实现接口的,用Cglib动态代理,Spring底层可以自动切换
Spring的AOP开发的相关术语
- 通知(Advice)
- 就是你需要实现的功能,也就是上面说的安全,事物,日志等。你可以先定义好,然后在想用的地方用一下。
- 连接点(JoinPoint)
- spring允许你使用通知的地方,基本每个方法的前,后(两者都有也行),,或抛出异常时都可以是连接点,spring只支持方法连接点和方法有关的前后(抛出异常),都是连接点。
- 切入点(Pointcut)
- 上面说的连接点的基础上,来定义切入点,你的一个类里,有5个方法,那就有5个连接点了,但是你并不想在所有方法附近都使用通知(使用叫织入),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
- 切面(Aspect)
- 切面是通知和切入点的结合。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
- 引入(introduction)
- 允许我们向现有的类添加新方法属性。就是把切面(也就是新方法属性:通知定义的)用到目标类中。
- 目标(target)
- 引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。
- 代理(proxy)
- 怎么实现整套aop机制的,就是通过代理,织入增强功能后产生的代理对象。
- 织入(weaving)
- 把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时。
- 图像解释

Spring的AOP开发入门(基于XML开发)
- 引入AOP开发的相关包
- 引入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">
</beans>
-
配置切面类
<!-- 把要增强的目标交给Spring管理--> <bean id="userServiceImpl" class="com.spring.service.impl.UserServiceImpl"></bean> <!--把通知所在的类也交给Spring管理--> <!-- 配置aop切面 --> <bean id="myAspectj" class="com.spring.aspectj.MyAspectj"></bean> <aop:config> <!-- 切入点: 指定要被增强哪个类里面哪个方法;*:表示任何的修饰符或返回值类型 ; ..表示匹配add()方法中里面可以有任意参数 --> <aop:pointcut expression="execution(* com.spring.service.UserService.add(..))" id="p1"/> <!-- 配置切面 --> <aop:aspect ref="myAspectj"> <!-- 把check通知的织入切入点p1(目标类的方法之前) --> <aop:before method="check" pointcut-ref="p1"/> </aop:aspect> </aop:config> </beans> -
通知的类型
- 前置通知before:在目标方法执行之前的操作可以获取切入点的信息。
- 后置通知after-returning:在目标方法执行之后的操作获得目标方法的返回值。
- 环绕通知around:在目标方法执行之前和之后进行操作。
- 异常抛出通知after-throwing:在目标方法抛出异常时的操作(比如出现异常后进行回滚)。
- 最终通知after:无论是否有异常都会执行的,相当于try-catch-finally中的finally块。
<aop:config> <!-- 切入点: 指定要被增强哪个类里面哪个方法;*:表示任何的修饰符或返回值类型 ; ..表示匹配add()方法中里面可以有任意参数 --> <aop:pointcut expression="execution(* com.spring.service.UserService.add(..))" id="p1"/> <aop:pointcut expression="execution(* com.spring.service.UserService.select(..))" id="p2"/> <aop:pointcut expression="execution(* com.spring.service.UserService.selectReturn(..))" id="p3"/> <aop:pointcut expression="execution(* com.spring.service.UserService.update(..))" id="p4"/> <aop:pointcut expression="execution(* com.spring.service.UserService.delete(..))" id="p5"/> <aop:pointcut expression="execution(* com.spring.service.UserService.deleteAfter(..))" id="p6"/> <!-- 配置切面 --> <aop:aspect ref="myAspectj"> <!-- 把check通知的织入切入点p1(目标类的方法之前) --> <aop:before method="check" pointcut-ref="p1"/> <aop:after-returning method="back" pointcut-ref="p2"/> <aop:after-returning method="backReturn" pointcut-ref="p3" returning="obj"/> <!--obj名字取MyAspectj类中的backReturn(Object obj)--> <aop:around method="around" pointcut-ref="p4"/> <aop:after-throwing method="doException" pointcut-ref="p5"/> <aop:after method="doAfter" pointcut-ref="p6"/> </aop:aspect> </aop:config>//这是做增强功能的类 public class MyAspectj { public void check(){ //通知 System.out.println("--校验身份--"); } public void back(){ System.out.println("--之后执行--"); } public void backReturn(Object obj){ System.out.println("--之后执行,返回的数据:"+(String)obj); } public void around(ProceedingJoinPoint point) throws Throwable { //point用来接收切入点update() System.out.println("--之前操作--"); point.proceed(); //执行跌入点 System.out.println("--之后操作--"); } public void doException(){ //被增强的切入点报异常之后会执行,不报异常不会执行 System.out.println("--异常抛出了--"); } public void doAfter(){ System.out.println("--不管有没有异常始终都会执行--"); } } //使用场景:前置通知:转账之前校验用户名和密码及余额
切入点表示式语法
基于execution的函数完成的语法
execution([访问修饰符] 方法返回值 包名.类名.方法名(参数)),com.spring.service.UserServiceImpl.*(..) 开发中用的最多的是这种,对当前类下所有的方法做增强处理(场景:事务处理)。
Spring的AOP基于注解的开发
Spring注解的通知类型
开启注解的aop开发
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
前置通知:@Before
后置通知:@AfterReturning(value="execution()",returning="result")
环绕通知:@Around
异常抛出通知:@AfterThrowing(value="execution()",throwing="e")
最终通知:@After
增强类
package com.spring.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Value;
/**
* 这是做增强功能的类
*/
@Aspect //注解通知类,告知Spring这是通知所在的类
public class MyAspectj {
@Before(value = "execution(* com.spring.service.UserService.add(..))")
public void check(){ //通知
System.out.println("--校验身份--");
}
@AfterReturning(value = "execution(* com.spring.service.UserService.select(..))")
public void back(){
System.out.println("--之后执行--");
}
@AfterReturning(value = "execution(* com.spring.service.UserService.selectReturn(..))",returning = "obj")
public void backReturn(Object obj){
System.out.println("--之后执行,返回的数据:"+(String)obj);
}
@Around(value = "execution(* com.spring.service.UserService.update(..))")
public void around(ProceedingJoinPoint point) throws Throwable { //point用来接收切入点update()
System.out.println("--之前操作--");
point.proceed(); //执行跌入点
System.out.println("--之后操作--");
}
@AfterThrowing(value = "execution(* com.spring.service.UserService.delete(..))",throwing = "e") //e可以接收切入点抛出的异常
public void doException(Exception e){ //被增强的切入点报异常之后会执行,不报异常不会执行
System.out.println("--异常抛出了--");
System.out.println(e.toString());
}
@After(value = "execution(* com.spring.service.UserService.deleteAfter(..))")
public void doAfter(){
System.out.println("--不管有没有异常始终都会执行--");
}
}
配置文件:
<?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 definitions here -->
<!--开启AOP注解开发-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 把要增强的目标交给Spring管理-->
<bean id="userServiceImpl" class="com.spring.service.impl.UserServiceImpl"></bean>
<!--把通知所在的类也交给Spring管理-->
<!-- 配置aop切面 -->
<bean id="myAspectj" class="com.spring.aspectj.MyAspectj"></bean>
</beans>
实现AOP的第三种方式
第三种方式就是实现Spring中的API,来获得面向切面编程的能力。
首先需要写增强类BeforeLog来实现 MethodBeforeAdvice接口。MethodBeforeAdvice中的抽象方法before,就是xml配置中的前置通知before。如果还需要后置通知after-returning等,也可以采用多实现接口AfterReturningAdvice。
public class BeforeLog implements MethodBeforeAdvice,AfterReturningAdvice{
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
@Override
public void before(Method method, Object[] objects, Object object) throws Throwable {
System.out.println("对象为"+object.getClass().getName()+"方法名称为:"+method.getName());
}
//returnValue 返回值
//method被调用的方法
//args 被调用的方法的对象的参数
//target 被调用的目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("对象"+target.getClass().getName()+"的,方法名为:"+method.getName()+"返回值:"+returnValue);
}
}
配置文件中需要将增强类或被增强类都注册到spring容器中,然后再配置切入点和切面
<!--注册bean-->
<bean id="userService" class="com.aop.demo01.service.impl.UserServiceImpl"></bean>
<bean id="beforeLog" class="com.aop.demo01.aspect.BeforeLog"/>
<!--配置aop-->
<!--实现Spring 的API-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.aop.demo01.service.impl.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<!-- <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>-->
</aop:config>

浙公网安备 33010602011771号