Spring AOP在web应用中的使用方法实例

网友投稿 204 2022-12-19


Spring AOP在web应用中的使用方法实例

前言

之前的aop是通过手动创建代理类来进行通知的,但是在日常开发中,我们并不愿意在代码中硬编码这些代理类,我们更愿意使用DI和IOC来管理aop代理类。Spring为我们提供了以下方式来使用aop框架

一、以声明的方式配置AOP(就是使用xml配置文件)

1.使用ProxyFactoryBean的方式:

ProxyFactoryBean类是FactoryBean的一个实现类,它允许指定一个bean作为目标,并且为该bean提供一组通知和顾问(这些通知和顾问最终会被合并到一个AOP代理中)它和我们之前的ProxyFactory都是Advised的实现。

以下是一个简单的例子:一个学生和一个老师,老师会告诉学生应该做什么。

public class Student {

public void talk() {

System.out.println("I am a boy");

}

public void walk() {

System.out.println("I am walking");

}

public void sleep() {

System.out.println("I want to sleep");

}

}

老师类

public class Teacher {

private Student student;

public void tellStudent(){

student.sleep();

student.talk();

}

public Student getStudent() {

return student;

}

public void setStudent(Student student) {

this.student = student;

}

}

我们创建一个通知类,这个和之前是一样的SpringAOP中的通知类型以及创建

package cn.lyn4ever.aop;

import org.aspectj.lang.JoinPoint;

public class AuditAdvice implements MethodBeforeAdvice {

@Override

public void before(Method method, Object[] objects, @Nullable Object o) throws Throwable {

System.out.println("这个方法被通知了" + method.getName());

}

}

然后就使用spring的IOC来管理这个通知类,在xml配置文件中声明如下:

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:util="http://springframework.org/schema/util" xmlns:p="http://springframework.org/schema/p"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/util

https://springframework.org/schema/util/spring-util.xsd">

p:interceptorNames-ref="interceptorNames">

advice

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:util="http://springframework.org/schema/util" xmlns:p="http://springframework.org/schema/p"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/util

https://springframework.org/schema/util/spring-util.xsd">

p:interceptorNames-ref="interceptorNames">

p:interceptorNames-ref="interceptorNames">

advice

测试类

public static void main(String[] args) {

GenericXmlApplicationContext context = new GenericXmlApplicationContext();

context.load("application1.xml");

context.refresh();

Teacher teacher = (Teacher) context.getBean("teacherOne");

teacher.tellStudent();

}

运行结果没有问题

以上是通过直接创建通知的方式,接下来我们试一个创建一个切入点(因为以上是对类中所有方法都进行通知,这时我们使用切入点只对其中部分方法进行通知),在xml配置文件中添加如下。

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:util="http://springframework.org/schema/util" xmlns:p="http://springframework.org/schema/p"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/util

https://springframework.org/schema/util/spring-util.xsd">

p:interceptorNames-ref="interceptorNames">

advice

p:target-ref="student" p:interceptorNames-ref="interceptorAdvisorNames">

advisor

p:advice-ref="advice">

p:expression="execution(* talk*(..))"/>

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:util="http://springframework.org/schema/util" xmlns:p="http://springframework.org/schema/p"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/util

https://springframework.org/schema/util/spring-util.xsd">

p:interceptorNames-ref="interceptorNames">

p:interceptorNames-ref="interceptorNames">

advice

p:target-ref="student" p:interceptorNames-ref="interceptorAdvisorNames">

p:target-ref="student" p:interceptorNames-ref="interceptorAdvisorNames">

advisor

p:advice-ref="advice">

p:expression="execution(* talk*(..))"/>

p:advice-ref="advice">

p:expression="execution(* talk*(..))"/>

p:expression="execution(* talk*(..))"/>

上图中的那个aspectj表达式写错了,在代码中有正确的

2.使用aop名称空间

在xml中引入如下的名称空间,为了不被影响,我册了其他多余的名称空间。然后很普通地注入我们之前那三个bean

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd

">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd

">

在这个配置中,我们还可以配置其他类型的通知,但是这个method属性一定要写我们自定义的那个通知类中的方法

在aop:pointcut中写expression时还支持如下语法:

3.使用@AspectJ样式注解方式

虽然是通过注解的方式来声明注解类,但是还是需要在xml中配置一点点内容(通过注解的方式也可以配置,但是在springboot中要使用的话有更方便的方式)

为了方便,就只写了一个HighStudent,而且直接调用它的方法,不依赖于外部的teacher实例来调用

package cn.lyn4ever.aop.aspectj;

import cn.lyn4ever.aop.aopconfig.Teacher;

import org.springframework.stereotype.Component;

/**

* 声明这是一个SpringBean,由Spring来管理它

*/

@Component

public class HighStudent {

public void talk() {

System.out.println("I am a boy");

}

public void walk() {

System.out.println("I am walking");

}

/**

* 这个方法添加一个teacher来做为参数,为了配置后边切入点中的args()

* @param teacher

*/

public void sleep(Teacher teacher) {

System.out.println("I want to sleep");

}

}

创建切面类

package cn.lyn4ever.aop.aspectj;

import cn.lyn4ever.aop.aopconfig.Teacher;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

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 //声明交由spring管理

@Aspect //表示这是一个切面类

public class AnnotatedAdvice {

/*

创建切入点,当然也可以是多个

*/

@Pointcut("execution(* talk*(..))")

public void talkExecution(){}

@Pointcut("bean(high*)")//这里为什么是high,因为我们这回测试bean是highStudent

public void beanPoint(){}

@Pointcut("args(value)")

public void argsPoint(Teacher value){}

/*

创建通知,当然也可以是多个

这个注解的参数就是上边的切入点方法名,注意有的还带参数

这个通知方法的参数和之前一样,榀加JoinPoint,也可不加

*/

@Before("talkExecution()")

public void doSomethingBefore(JoinPoint joinPoint){

System.out.println("before: Do Something"+joinPoint.getSignature().getName()+"()");

}

/**

* 环绕通知请加上ProceedingJoinPoint参数 ,它是joinPoint的子类

* 因为你要放行方法的话,必须要加这个

* @param joinPoint

* @param teacher

*/

@Around("argsPoint(teacher) && beanPoint()")

public Object doSomethindAround(ProceedingJoinPoint joinPoint, Teacher teacher) throws Throwable {

System.out.println("Around: Before Do Something"+joinPoint.getSignature().getName()+"()");

Object proceed = joinPoint.proceed();

System.out.println("Around: After Do Something"+joinPoint.getSignature().getName()+"()");

return proceed;

}

}

xml中配置开启扫描注解

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd http://springframework.org/schema/context https://springframework.org/schema/context/spring-context.xsd">

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:aop="http://springframework.org/schema/aop"

xmlns:context="http://springframework.org/schema/context"

xsi:schemaLocation="http://springframework.org/schema/beans

http://springframework.org/schema/beans/spring-beans.xsd

http://springframework.org/schema/aop

http://springframework.org/schema/aop/spring-aop.xsd http://springframework.org/schema/context https://springframework.org/schema/context/spring-context.xsd">

使用java注解配置的方式配置扫描注解

@Configuration //声明这是一个配置类

@ComponentScan("cn.lyn4ever.aop.aspectj")

@EnableAspectJAutoProxy(proxyTargetClass = true)//相当于xml中的

public class BeanConfig {

}

测试方法

package cn.lyn4ever.aop.aspectj;

import cn.lyn4ever.aop.aopconfig.Teacher;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.support.GenericApplicationContext;

import org.springframework.context.support.GenericXmlApplicationContext;

public class AspectMain {

public static void main(String[] args) {

// xmlConfig();

javaConfig();

}

private static void javaConfig() {

GenericApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);

HighStudent student = (HighStudent) context.getBean("highStudent");

student.sleep(new Teacher());//应该被环绕通知

System.out.println();

student.talk();//前置通知

System.out.println();

student.walk();//不会被通知

System.out.println();

}

private static void xmlConfig(){

GenericXmlApplicationContext context = new GenericXmlApplicationContext();

context.load("application_aspect.xml");

context.refresh();

HighStudent student = (HighStudent) context.getBean("highStudent");

student.sleep(new Teacher());//应该被环绕通知

System.out.println();

student.talk();//前置通知

System.out.println();

student.walk();//不会被通知

System.out.println();

}

}

项目代码地址,如果觉得还不错的话,给个star吧

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何使用Spring AOP的通知类型及创建通知
下一篇:Java基于final修饰数据过程解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~