Spring框架—AOP总结&整合日志

AOP

概念

面向切面编程。 在软件业, AOP Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护 的一种技术。

功能

利用 AOP 可以对 业务逻辑 的各个部分进行隔离,从而使得业务逻辑各部分之间的 耦合度 降低,提高程序的 可重用性 ,同时提高了开发的效率。

作用

AOP影响的是Service层

  • 日志记录,
  • 性能统计,
  • 安全控制,
  • 事务处理
  • 异常处理

半自动AOP

  • target:目标类——》如UserServiceImpl.class;需要扩展的类;
  • joinpoint:连接点——》目标类中所有的方法;
  • pointcut: 切入点——》如:insertS;连接点中的具体要扩展的某个方法;
  • advisor: 增强(通知)——》切入点需要进行的扩展;
  • weaver:织入——》将增强应用到切入点的过程;
  • proxy:代理对象——》织入以后生成的代理对象;
  • aspect: 切面——》多个连接点连成一个面;

AOP增强分类

增强代码出现的位置

  • 前置增强: 在目标方法执行前进行增强;
  • 后置增强: 在目标方法执行后进行增强;
  • 环绕增强: 前后都增强;
  • 异常增强: 抛出异常后进行功能增强;
  • 引介增强: 可以为目标类增加方法和属性;(基本不用)
try {
// 前置
// 目标方法 ;
// 后置
} catch {
// 异常增强;
}  

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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 开启包扫描:开启后的包中的类添加@Component就可以交给spring容器管理
注意:
1、此处写的是包名;
2、多个的话使用,进行分隔;
-->
<context:component-scan base-package="cn.ry.pojo,cn.ry.dao">
</context:component-scan>
<!-- 半自动aop进行配置: -->
<!-- 1、将目标类交给spring容器来管理 ; -->
<bean id="service" class="cn.ry.service.impl.UserServiceImpl"></bean>
<!-- 3、将增强类交给spring容器管理: -->
<bean id="advisor1" class="cn.ry.advisor.Advisor1"></bean>
<!-- 2、依赖于代理工厂类进行配置 -->
<bean id="proxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!--target:属性指的是目标类 -->
<property name="target" ref="service"></property>
<!-- 向代理工厂类注入增强: -->
<property name="interceptorNames" value="advisor1"></property>
<!-- 表示的是是否强制使用cglib动态代理:
true强制;
false:不是;
-->
<property name="optimize" value="false"></property>
</bean>
</beans>

 java代码增强

package cn.ry.advisor;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
*
* <p>Title: Advisor1</p>
* <p>Description:模拟半自动aop的环绕增强;不同增强接口不同 </p>
* @author dzc
* @date 2024年6月5日
*/
public class Advisor1 implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// TODO Auto-generated method stub
//编写之前的增强内容:
long before = System.currentTimeMillis();
//重写方法内容:
arg0.proceed();
long after= System.currentTimeMillis();
System.out.println("执行时间为"+(after-before)+"ms");
return null;
}
}

总结

优点
代替了 ProxyFactory 里面复杂的两种代理方式,通过 spring ProxyFactoryBean 实体类中的 target 属性和interceptorNames 属性将目标类和增强类注入其中,即可生效。
缺点
  • 每一个bean都需要配置一个ProxyFactoryBean这样的配置,很麻烦;
  • 增强需要实现不同的接口,增加了耦合度;
  • 同种类型bean在容器中有多个;
  • 织入过程没看到,需要将增强和目标类注入到ProxyFactoryBean中,手动织入;
  • 没办法找到具体的切入点,是对目标类中所有的方法进行增强,不合理。

传统AOP

添加 jar: aopalliance.jar;
自动织入的 jar:aspectjweaver- 版本号 ;
  • 确定目标类;
  • 确定增强类;
  • 确定切入点;
  • 自动织入;

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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/springcontext.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 开启包扫描:开启后的包中的类添加@Component就可以交给spring容器管理
注意:
1、此处写的是包名;
2、多个的话使用,进行分隔;
-->
<context:component-scan base-package="cn.ry.pojo,cn.ry.dao">
</context:component-scan>
<!-- 传统aop进行配置: -->
<!-- 1、将目标类交给spring容器来管理 ; -->
<bean id="service" class="cn.ry.service.impl.UserServiceImpl">
</bean>
<!-- 2、将增强类交给spring容器管理: -->
<bean id="advisor1" class="cn.ry.advisor.Advisor1"></bean>
<!-- aop配置 主要确定切入点和织入 -->
<!-- proxy-target-class="false"为false的时候表示默认jdk动态代理;
为true的时候,强制使用cglib动态代理;
-->
<aop:config proxy-target-class="false">
<!-- 配置aop的切入点
id指的是唯一标识;
expression指的是切入点表达式:
execution(* cn.ry.service.impl.UserServiceImpl.方法
名字(..))
java
没进行任何改变;
总结
优点
采用切入点表达式,可以找到具体的需要增强的方法,从而进行增强;
采用了自动织入的方式,省略了ProxyFactoryBean的配置;
缺点
java代码并未改动,存在增强硬编码的问题;
基于AspectJ的aop
 AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器
用来生成遵守Java字节编码规范的Class文件。
添加依赖包: spring-aspects;
增强类型
前置
后置
环绕
异常
引介
最终
核心特点
增强类本身不依赖于任何框架,也就是不需要去实现任何接口,普通的java类也能作为增强类。
xml版本
增强类
格式: 修饰符 返回结果 包名.类名.方法名(形参);
修饰符很一般省略
返回结果: 无返回是void *代表的是任意类型;
cn.ry.*.impl.*. cn.ry.下面的所有dao和service的实现类中
的所有类都被选中;
方法: select*(..) 表示的是所有select开头的方法;
-->
<aop:advisor advice-ref="advisor1" pointcut="execution(*
cn.ry.service.*.*.insert*(..))"/>
</aop:config>
</beans>

java代码没进行任何改变

总结

优点
  • 采用切入点表达式,可以找到具体的需要增强的方法,从而进行增强;
  • 采用了自动织入的方式,省略了ProxyFactoryBean的配置;
缺点
  • java代码并未改动,存在增强硬编码的问题;

基于AspectJ的AOP

添加依赖包 : spring-aspects;

概念

AspectJ 是一个面向 切面 的框架,它扩展了 Java 语言。 AspectJ 定义了 AOP 语法,它有一个专门的 编译器 用来生成遵守 Java 字节编码规范的 Class 文件。

增强类型

  • 前置
  • 后置
  • 环绕
  • 异常
  • 引介
  • 最终
核心特点
  • 增强类本身不依赖于任何框架,也就是不需要去实现任何接口,普通的java类也能作为增强类。

XML版本

增强类
package cn.ry.advisor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
//增强类:
public class Advisor2 {
//前置增强的方法:
//方法可以有参;可以无参
//如果有参只能是JoinPoint:主要用来获取目标方法名字;
public void before(JoinPoint point) {
String name = point.getSignature().getName();
System.out.println(name+"before--------------------");
}
//环绕增强必须有返回值;
// 环绕增强参数必须有ProceedingJoinPoint
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("前-------");
Object obj = point.proceed();
System.out.println("后-------");
return obj;
}
//后置增强:
//后置增强的参数:
//第一个参数JoinPoint
//第二个参数用来接收目标方法的返回结果,放到第二参数中;
public Object afterReturning(JoinPoint point,Object obj) {
String name = point.getSignature().getName();
System.out.println(name+"afterReturning--------------------"+obj);
return obj;
}
//异常增强:
public void afterThrowing(JoinPoint point,Throwable ex) {
String name = point.getSignature().getName();
System.out.println(name+"afterThrowing--------------------
"+ex.getMessage());
}
//最终增强
public void after() {
System.out.println("最终增强哈哈哈---------");
}
}
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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
注解版本
需要在xml中开启包扫描;
设置aspectj自动代理
">
<!-- 开启包扫描:开启后的包中的类添加@Component就可以交给spring容器管理
注意:
1、此处写的是包名;
2、多个的话使用,进行分隔;
-->
<context:component-scan base-package="cn.ry.pojo,cn.ry.dao">
</context:component-scan>
<!-- 传统aop进行配置: -->
<!-- 1、将目标类交给spring容器来管理 ; -->
<bean id="service" class="cn.ry.service.impl.UserServiceImpl">
</bean>
<!-- 2、将增强类交给spring容器管理: -->
<bean id="advisor2" class="cn.ry.advisor.Advisor2"></bean>
<!-- 3、aop配置发生改变: -->
<aop:config proxy-target-class="false">
<!-- aop:aspect 中的ref表示的是引入进来的增强; -->
<aop:aspect ref="advisor2">
<!-- 设置的切入点: -->
<aop:pointcut expression="execution(* cn.ry.service.*.*.*
(..))" id="p1"/>
<!--
aop:around:环绕增强 Method属性指的是方法名;环绕增强的方法要求
返回值是Object;
-->
<aop:around method="around" pointcut-ref="p1"/>
<!-- 前置: -->
<aop:before method="before" pointcut-ref="p1"/>
<!-- 后置:
returning=""放的是后置增强方法中第二个参数的形参;
-->
<aop:after-returning method="afterReturning" pointcutref="p1" returning="obj"/>
<!-- 异常: -->
<aop:after-throwing method="afterThrowing" pointcut-ref="p1"
throwing="ex"/>
<!-- 最终: -->
<aop:after method="after" pointcut-ref="p1"/>
</aop:aspect>
</aop:config>
</beans>

注解版本

  • 需要在xml中开启包扫描;
  • 设置aspectj自动代理
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 开启包扫描:开启后的包中的类添加@Component就可以交给spring容器管理
注意:
1、此处写的是包名;
2、多个的话使用,进行分隔;
-->
<context:component-scan base-package="cn.ry.service,cn.ry.advisor">
</context:component-scan>
<!-- 开启aop自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectjautoproxy>
</beans>
  • 在增强类上添加@Aspect注解;
package cn.ry.advisor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//增强类:
@Component
@Aspect //声明当前是增强类;
public class Advisor2 {
//主要是相当于xml中配置切入点:
//value中写的是expression表达式
@Pointcut(value = "execution(* cn.ry.service.*.*.*(..))")
public void a() {
}
//前置增强的方法:
//方法可以有参;可以无参
//如果有参只能是JoinPoint:主要用来获取目标方法名字;
@Before(value = "a()")
public void before(JoinPoint point) {
String name = point.getSignature().getName();
System.out.println(name+"before--------------------");
}
//环绕增强必须有返回值;
// 环绕增强参数必须有ProceedingJoinPoint
@Around(value = "a()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("前-------");
Object obj = point.proceed();
整合日志
指的是spring去整合日志框架。
log4j2:
需要导入jar包; log4j-core 、 log4j-api;
配置文件:log4j2.xml;
将jar包和配置文件导入进来以后,运行即可(要求spring导入对应的jar包:spring-test.jar、junit、
hamcrest)。
测试
白盒测试、黑盒测试。
白盒测试也就是结构测试、 透明盒测试、逻辑驱动测试或基于代码的测试,也就相当于平时debug进行
调试、测试。
黑盒测试也就是功能测试,主要用户按照 需求规格说明书进行使用,检查看一下能够正常运行此功能。
Junit
System.out.println("后-------");
return obj;
}
//后置增强:
//后置增强的参数:
//第一个参数JoinPoint
//第二个参数用来接收目标方法的返回结果,放到第二参数中;
@AfterReturning(value="a()")
public Object afterReturning(JoinPoint point,Object obj) {
String name = point.getSignature().getName();
System.out.println(name+"afterReturning--------------------"+obj);
return obj;
}
//异常增强:
@AfterThrowing(value="a()")
public void afterThrowing(JoinPoint point,Throwable ex) {
String name = point.getSignature().getName();
System.out.println(name+"afterThrowing--------------------
"+ex.getMessage());
}
//最终增强
@After(value="a()")
public void after() {
System.out.println("最终增强哈哈哈---------");
}
}

整合日志

概念

指的是 spring 去整合日志框架。

导入jar

log4j-core log4j-api;

配置文件:

log4j2.xml;
jar 包和配置文件导入进来以后,运行即可(要求 spring 导入对应的 jar 包: spring-test.jar junit
hamcrest )。

本次分享就到这里,博主创作不易,你的关注是我坚持更新源源不断的动力。点个关注不迷路,感谢家人们!!!我们下次见

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值