当前位置: 移动技术网 > IT编程>开发语言>Java > Sprin_AOP的学习使用

Sprin_AOP的学习使用

2020年07月31日  | 移动技术网IT编程  | 我要评论

Spring的AOP简介

  1. 什么是AOP?
    Aspect Oriented Programming的缩写,面向切面编程,通过预编译的方式在程序运行期通过动态代理实现程序功能统一维护的技术。
  2. AOP的作用及优势
    作用:程序运行期间,不修改源代码的情况下对方法的功能进行增强优势
    优势:降低代码重复率、提高开发效率、方便后期维护
  3. AOP的底层原理
    AOP的底层通过spring的动态代理技术实现。在程序运行期,spring通过动态代理技术动态的产生代理对象,在执行代理对象的方法时进行增强功能的介入,去调用目标对象的方法,完成功能的增强。
    1. 基于jdk的动态代理(基于接口,有接口时使用)
      案列
//1.定义目标类接口
public interface TargetInterface {
    void run();
}
//2.定义目标类实现接口
public class Target implements TargetInterface {
    @Override
    public void run() {
        System.out.println("真实对象");
    }
}
//3.定义增强类
public class Advice {
    public void before(){
        System.out.println("前置增强");
    }
    public void after(){
        System.out.println("后置增强");
    }
}
//4.定义测试类
public class Test {
    public static void main(String[] args) {
        //1.创建真实对象
        final Target target = new Target();
        //创建增强对象
        final Advice advice = new Advice();
        //2. 创建真实对象
        TargetInterface proxyTarget = (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标对象的类加载器
                target.getClass().getInterfaces(), //目标对象相同的接口字节码对象数组
                new InvocationHandler() {//处理器
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //前置增强
                        advice.before();
                        Object invoke = method.invoke(target, args);
                        //后置增强
                        advice.after();
                        return invoke ;
                    }
                });
        //调用代理对象的方法
        proxyTarget.run();
    }
}

2. 基于cglib的动态代理(基于父类,无接口使用)
//1.定义目标类
public class Target  {
    public void run() {
        System.out.println("真实对象");
    }
}
//2. 定义增强类
public class Advice {
    public void before(){
        System.out.println("前置增强");
    }
    public void after(){
        System.out.println("后置增强");
    }
}

//3. 定义i测试类
public class ProxyTest {
    public static void main(final String[] args) {
        //1.目标对象
        final Target target = new Target();
        //2. 增强对象
        final Advice advice = new Advice();
        //3.返回值 动态生成的代理对象
        //3.1 创建增强其
        Enhancer enhancer = new Enhancer();
        //3.2 设置父类(目标)
        enhancer.setSuperclass(Target.class);
        //3.3 设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                advice.before();
                Object invoke = method.invoke(target, args);//执行目标
                advice.after();
                return invoke;
            }
        });
        Target proxy = (Target) enhancer.create();
        proxy.run();
    }
}
  1. AOP相关术语
单词 术语 含义
Target 目标对象 代理的目标对象,被代理对象
Proxy 代理对象 代理的动作
JoinPoint 连接点 被代理拦截到的所以方法
PointCut 切入点 对连接点进行拦截的定义
Advice 通知 指拦截到连接点之后要执行的代码
Aspect 切面 切入点和通知的结合,切面就是对横切关注点的抽象
横切关注点 对哪些方法进行拦截,拦截后怎么处理 ,这些关注点称之为横切关注点
Weave 织入 将切面应用到目标对象并导致代理对象创建的过程
Introduction 引入 在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。

基于 XML 的 AOP 开发

  1. 实现步骤
    1. 导入AOP的坐标
    2. 创建目标接口和目标类
    3. 创建切面类
    4. 将目标类和切面类的对象创建权叫给spring
    5. 在配置文件中配置织入(weave)关系
    6. 创建测试类
    相关代码:
//1.pom池中的相关坐标
    <!--导入spring的context坐标,context依赖aop-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <!-- aspectj的织入 -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>
    <!-- spring整合junit  (测试用) -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>

//2.目标接口及目标类
public interface TargetInterface {
    void method();
}
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target目标运行中");
    }
}

//3. 增强类
public class MyAspect {
    //前置增强方法
    public void before(){
        System.out.println("前置代码增强.....");
    }
    //后置增强方法
    public void after(){
        System.out.println("后置增强方法");
    }
}

//4. applicationContext.xml
<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/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
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">    
</beans>
<!--  配置目标类  -->
    <bean id="target" class="com.itheima.aop.Target"></bean>
<!--   配置切面类 -->
    <bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
<!--  配置织入关系  -->
    <aop:config>
<!--  myAspect的Bean为切面对象  -->
        <aop:aspect ref="myAspect">
            <aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.method())"></aop:before>
            <aop:after method="after" pointcut="execution(public void com.itheima.aop.Target.method())"></aop:after>
        </aop:aspect>
    </aop:config>

//5.测试类
@RunWith(SpringJUnit4ClassRunner.class)//替换运行期
@ContextConfiguration("classpath:applicationContext.xml")//指定配置文件
public class AopTest {
    @Autowired//注入测试对象
    private TargetInterface target;
    @Test
    public void test(){
        target.method();
    }
}


在这里插入图片描述

  1. 切点表达式
    1. 语法:
    execution([修饰符]返回值类型 包名.类命.方法名(参数))
    2. 注意
    * 访问修饰符可以省略不写
    * 返回值类型,包名,类命,方法名可以使用*代表,表示任意
    * 包名和类命之间一个点.代表当前包下的类,两个…表示当前包及其子包下的类
    * 参数列表可以使用两个点…表示任意个数及类型的参数
  2. 通知的类型
    通知的配置语法:
<aop:通知类型 method=“切面类中方法名” pointcut=“切点表达式"></aop:通知类型>
名称 标签 说明
前置通知 before 用于配置前置通知。指定增强的方法在切入点方法之前执行
后置通知 after-returning 用于配置后置通知。指定增强的方法在切入点方法之后执行
环绕通知 around 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
异常抛出通知 afterThrowing 用于配置异常抛出通知。指定增强的方法在出现异常时执行
最终通知 after 用于配置最终通知。无论增强方式执行是否有异常都会执行
//增强类

 //前置增强方法
    public void before(){
        System.out.println("前置代码增强.....");
    }
    //后置增强方法
    public void afterReturning(){
        System.out.println("后置增强方法");
    }
    //环绕通知
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = pjp.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }
    //异常通知
    public void afterThrowing(){
        System.out.println("异常时抛出增强");
    }
    //最终增强
    public void after(){
        System.out.println("最终通知");
    }

//xml
            <aop:before method="before" pointcut="execution(public void com.itheima.aop.Target.method())"></aop:before>
            <aop:after-returning method="afterReturning" pointcut="execution(public void com.itheima.aop.*.*(..))"></aop:after-returning>
            <aop:around method="around" pointcut="execution(public void com.itheima.aop.*.*(..))"></aop:around>
            <aop:after-throwing method="afterThrowing" pointcut="execution(public void com.itheima.aop.*.*(..))"></aop:after-throwing>
            <aop:after method="after" pointcut="execution(public void com.itheima.aop.*.*(..))"></aop:after>
  1. 切点表达式的抽取
    当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。
<aop:config>
    <!--引用myAspect的Bean为切面对象-->
    <aop:aspect ref="myAspect">
        <aop:pointcut id="myPointcut" expression="execution(* com.itheima.aop.*.*(..))"/>
        <aop:before method="before" pointcut-ref="myPointcut"></aop:before>
    </aop:aspect>
</aop:config>

基于注解的AOP开发

  1. 开发步骤
    ①创建目标接口和目标类(内部有切点)

    ②创建切面类(内部有增强方法)

    ③将目标类和切面类的对象创建权交给 spring

    ④在切面类中使用注解配置织入关系

    ⑤在配置文件中开启组件扫描和 AOP 的自动代理

    ⑥测试

  2. 相关代码

//1.目标类接口及目标类
public interface TargetInterface {
    void method();
}
//注解标注目标类,加入sprin容器
@Component("target")
public class Target implements TargetInterface {
    @Override
    public void method() {
        System.out.println("Target目标运行中");
    }
}

//定义切面类
@Component("myAspect")
@Aspect
public class MyAspect {
    //切点表达式的抽取
    @Pointcut("execution(* com.itheima.anno.*.*(..))")
    public void pointcut(){}
    //前置增强方法
    @Before("execution(* com.itheima.anno.*.*(..))")
    public void before(){
        System.out.println("前置代码增强.....");
    }

    //后置增强方法  注解-表达式的抽取
    @After("pointcut()")
    public void afterReturning(){
        System.out.println("后置增强方法");
    }
    //环绕通知  注解-表达式的抽取
    @Around("MyAspect.pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = pjp.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }
    //异常通知
    public void afterThrowing(){
        System.out.println("异常时抛出增强");
    }
    //最终增强
    public void after(){
        System.out.println("最终通知");
    }

}


//测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-anno.xml")
public class AnnoTest {
    @Autowired
    private TargetInterface target;
    @Test
    public void test(){
        target.method();
    }
}

  1. 注解通知类型
    语法:@通知注解(“切点表达式”)
    属性参考 通知的配置

  2. 切点表达式的抽取
    同 xml配置aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。

  3. 步骤
    ①使用@Aspect标注切面类
    ②使用@通知注解标注通知方法
    ③在配置文件中配置aop自动代理aop:aspectj-autoproxy/

本文地址:https://blog.csdn.net/qq_44275894/article/details/107693507

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网