Spring入门—SpringAop
一、springAop术语
springAop:面向切面编程。可插拔式的。即各个方法模块独立。需要就添加配置,不需要时就删除配置。
- 切面(Aspect):横切关注点被模块化的特殊对象,即要插入的功能。
- 通知(Advice):店面必须要完成的工作,所谓通知是指拦截到joinpoint之后要做的事情。
- 通知分为:前置通知、后置通知、异常通知、最终通知、和环绕通知。
- 目标(target):被通知的对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 连接点(JoinPoint):程序执行的某个特定位置。eg:类的某个方法运行前、调用后、方法抛出异常后等。
- 连接点有两个信息要确定,一个是方法(程序执行点),即执行什么样的方法时需要连接。
- 另一个就是方位(程序相对点),即在什么时候连接,是方法执行前、执行后还是抛出异常后等。
- 切点(PointCut):每个类都拥有多个连接点,那么切点就是用来定位到特殊连接点的。
- 类比:连接点相当于数据库中的记录,而切点相当于查询条件。
- 织入(Weaving):是指把切面应用到目标对象来创建新的代理对象的过程,切面怎么指定的连接点织入到目标对象。
- 引入(Introduction):在不修改代码的前提下,Introduction可以在运行期为类动态的添加一些方法或Filed。
二、springAop快速入门—案例(这里使用注解方案)
1. 导入相关依赖包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2. 编写计算器接口(Calculator.java)
public interface Calculator {
public int plus(int x, int y, int z);
public double plus(double x, double y);
public int plus(int x, int y);
public int substract(int x, int y);
public int division(int x,int y);
public int multiplication(int x,int y);
}
3. 编写计算器类继承上面的接口(HxCalculator.java)
@Component //這裏一定要加上注解,説明這是一個組件
public class HxCalculator implements Calculator{
@Override
public int plus(int x, int y, int z) {
return x + y + z;
}
@Override
public double plus(double x, double y) {
return x + y;
}
@Override
public int plus(int x, int y) {
int result = x + y;
return result;
}
@Override
public int substract(int x, int y) {
int result = x - y;
return result;
}
@Override
public int division(int x, int y) {
int result = x / y;
return result;
}
@Override
public int multiplication(int x, int y) {
int result = x * y;
return result;
}
}
4. 编写日志工具类(LogUtil.java)
public class LogUtil {
public static Logger log = Logger.getLogger(LogUtil.class);
}
5. 编写日志切面类(LoggingAspect.java)
/**
* 日志切面
* @author Huathy
* @date 2020年3月5日
*/
@Order(1) //如果同时有多个切面,可以通过@Order注解来解决切面的先后顺序,值越小优先级越高
@Component //这个切面我们需要放到ioc容器中,所以需要加上注解@Componet
@Aspect //将这个类声明为切面
public class LoggingAspect {
/**
* 前置通知
* @param jp
*/
@Before("execution(public int com.hx.springaop.impl.HxCalculator.plus(int,int))")
public void beforeMethod(JoinPoint jp){
String methodName = jp.getSignature().getName();
LogUtil.log.info( "前置通知-方法" + methodName + "開始執行,參數為" + Arrays.toString(jp.getArgs()) );
}
/**
* 后置通知
* @param jp
*/
@After("execution(public * com.hx.springaop.impl.HxCalculator.plus(..))")
public void afterMethod(JoinPoint jp){
String methodName = jp.getSignature().getName();
LogUtil.log.info( "后置通知-方法" + methodName + "運行結束..." );
}
@Pointcut("execution(public * com.hx.springaop.impl.HxCalculator.*(..))")
public void logging(){}
/**
* 返回通知
* @param jp
* @param result
*/
@AfterReturning(value="logging()", returning="result")
public void afterReturnMethod(JoinPoint jp,Object result){
String methodName = jp.getSignature().getName();
LogUtil.log.info( "返回通知-方法" + methodName + "運行結束,返回結果為:" + result );
}
/**
* 异常通知
* @param jp
* @param e
*/
@AfterThrowing(value="logging()", throwing="e")
public void afterThrowMethod(JoinPoint jp, Exception e){
String methodName = jp.getSignature().getName();
LogUtil.log.info( "异常通知-方法" + methodName + "出現異常信息:" + e );
}
/**
* 环绕通知
* @param pjp
* @return
*/
@Around("logging()")
public Object around(ProceedingJoinPoint pjp){
Object obj = null;
String methodName = pjp.getSignature().getName();
LogUtil.log.info( "環繞通知-方法" + methodName + "開始執行,參數:" + Arrays.toString(pjp.getArgs()) );
try {
obj = pjp.proceed(); //运行方法
LogUtil.log.info( "環繞通知-方法" + methodName + "運行結束,結果:" + obj );
} catch (Throwable e) {
LogUtil.log.info( "環繞通知-方法" + methodName + "運行出現異常信息:" + e );
e.printStackTrace();
}
return obj;
}
}
6. 在资源包下编写全局配置spring-beans.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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置扫描路径 -->
<context:component-scan base-package="com.hx.springaop" />
<!-- 讓注解起作用 -->
<aop:aspectj-autoproxy />
</beans>
7. 把log4j.properties放到资源包下
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=hx.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %m%n
log4j.rootLogger=debug, stdout, file
8. 编写测试类
public class AppTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
Calculator clt = (Calculator) context.getBean("hxCalculator");
System.out.println( clt.plus(10, 20) );
System.out.println( clt.plus(10, 20, 30) );
System.out.println( clt.plus(10.1, 10.2) );
System.out.println( clt.substract(10, 20) );
System.out.println( clt.division(10, 0) );
}
}
9. 项目目录结构
三、上述案例(xml配置方案)
1.把上面所有类上的通知组件等注解删除
2.修改spring-beans.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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 计算器类 -->
<bean id="calculator" class="com.hx.springaop.impl.HxCalculator"></bean>
<!-- 切面类 -->
<bean id="logAspect" class="com.hx.springaop.util.LoggingAspect"></bean>
<!-- 配置aop -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut id="pointcut1" expression="execution(public int com.hx.springaop.impl.HxCalculator.plus(int,int))"></aop:pointcut>
<aop:pointcut id="pointcut2" expression="execution(public * com.hx.springaop.impl.HxCalculator.*(..))"></aop:pointcut>
<!-- 配置切面通知。ref:应用的切面id。 -->
<aop:aspect ref="logAspect" order="1">
<!-- 配置通知类型对应调用的方法以及切点 -->
<aop:before method="beforeMethod" pointcut-ref="pointcut1"></aop:before>
<aop:after method="afterMethod" pointcut-ref="pointcut2"></aop:after>
<aop:after-returning method="afterReturnMethod" pointcut-ref="pointcut2" returning="result"></aop:after-returning>
<aop:after-throwing method="afterThrowMethod" pointcut-ref="pointcut2" throwing="e"></aop:after-throwing>
<aop:around method="around" pointcut-ref="pointcut2"></aop:around>
</aop:aspect>
</aop:config>
</beans>
3. 修改测试类
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
Calculator clt = (Calculator) context.getBean("calculator");
System.out.println( clt.plus(10, 20) );
System.out.println( clt.plus(10, 20, 30) );
System.out.println( clt.plus(10.1, 10.2) );
System.out.println( clt.substract(10, 20) );
System.out.println( clt.division(10, 0) );
}
转载:https://blog.csdn.net/qq_40366738/article/details/104699572
查看评论