Spring基础学习——4.Spring的AOP简介

2021-02-05

4、Spring的AOP简介

4.1、AOP的作用及其优势

image-20210205135830691

image-20210205140218705

image-20210205140225278

image-20210205140545668

image-20210205140756053

image-20210205141124833

基于jdk的动态代理的实现

目标接口及其实现类

package com.xiaobo.proxy.jdk;
​
public interface TargetInterface {
    public void save();
}
package com.xiaobo.proxy.jdk;
​
public class Target implements TargetInterface{
​
    @Override
    public void save() {
        System.out.println("小波实现了");
    }
}

Advice增强类

package com.xiaobo.proxy.jdk;
​
public class Advice {
​
    public void before(){
        System.out.println("前置增强");
    }
    public void afterReturning(){
        System.out.println("后置增强");
    }
​
}

ProxyTest测试类

package com.xiaobo.proxy.jdk;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
public class ProxyTest {
    public static void main(String[] args) {
        //创建目标对象
        final Target target=new Target();
        //获得增强对象
        Advice advice=new Advice();
        //返回值 动态生成的代理对象
        TargetInterface proxy=(TargetInterface) Proxy.newProxyInstance(
                //目标对象的类加载器
                target.getClass().getClassLoader(),
                //目标对象相同的接口字节码对象数组
                target.getClass().getInterfaces(),
                //接口
                new InvocationHandler() {
                    //调用代理对象的任何方法 实质执行的都是invoke方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //前置增强
                        advice.before();
                        //执行目标方法 执行谁的,实际参数
                        Object invoke = method.invoke(target, args);
                        //后置增强
                        advice.afterReturning();
                        return null;
                    }
                }
        );
        //调用代理对象方法
        proxy.save();
    }
}

Cglib的实现类

package com.xiaobo.proxy.cglib;
​
import com.xiaobo.proxy.jdk.TargetInterface;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
public class ProxyTest {
    public static void main(String[] args) {
        //创建目标对象
        final Target target=new Target();
        //获得增强对象
        Advice advice=new Advice();
        //返回值 动态生成的代理对象 基于cglib
        //1、创建增强器cglib
        Enhancer enhancer=new Enhancer();
        //2、设置父类(目标)
        enhancer.setSuperclass(Target.class);
        //3、设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                //执行前置
                advice.before();
                Object invoke = method.invoke(target, args);
                //执行后置
                advice.afterReturning();
                return invoke;
            }
        });
        //4、创建、生成代理对象
        Target proxy = (Target)enhancer.create();
        proxy.save();
    }
}

4.2、AOP的相关概念

image-20210205145220291

image-20210205145831518

image-20210205145935522

4.3、基于XML的AOP开发

image-20210205150324725

aspectj实现了AOP

Bean配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>org.example</groupId>
    <artifactId>xiaobo_spring_aop</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
</project>

测试类

package com.xiaobo.test;
​
import com.xiaobo.aop.TargetInterface;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
​
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private TargetInterface target;
    @Test
    public void test1(){
        target.save();
    }
}

applicationContext.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">
​
    <!--目标对象-->
    <bean id="target" class="com.xiaobo.aop.Target"></bean>
    <!--切面对象-->
    <bean id="myAspect" class="com.xiaobo.aop.MyAspect"></bean>
​
    <!--配置织入 告诉Spring框架 那些方法(切点)需要进行哪些增强(前置增强、后置增强)-->
    <aop:config>
        <!--声明切面-->
        <aop:aspect ref="myAspect">
            <!--切面:切点+通知-->
            <aop:before method="before" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:before>
            <!--后置增强-->
        </aop:aspect>
    </aop:config>
</beans>

切点表达式

<aop:before method="before" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:before>

切点表达式如何配置

image-20210205163415665

通知种类

image-20210206160257585

Target目标方法

package com.xiaobo.aop;
​
​
public class Target implements TargetInterface {
​
    @Override
    public void save() {
​
        System.out.println("小波实现了");
        //创造异常
        int i=1/0;
    }
}

MyAspect增强方法

package com.xiaobo.aop;
​
import org.aspectj.lang.ProceedingJoinPoint;
​
public class MyAspect {
​
    public void before(){
        System.out.println("前置增强");
    }
​
    public void afterReturning(){
        System.out.println("后置增强...");
    }
    //Proceeding JoinPoint: 正在执行的连接点===切点
    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("最终增强....");
    }
}

applicationContext配置文件

<?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 id="target" class="com.xiaobo.aop.Target"></bean>
    <!--切面对象-->
    <bean id="myAspect" class="com.xiaobo.aop.MyAspect"></bean>
​
    <!--配置织入 告诉Spring框架 那些方法(切点)需要进行哪些增强(前置增强、后置增强)-->
    <aop:config>
        <!--声明切面-->
        <aop:aspect ref="myAspect">
            <!--切面:切点+通知-->
<!--            <aop:before method="before" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:before>-->
            <!--后置增强-->
<!--            <aop:before method="afterReturning" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:before>-->
            <aop:around method="around" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:around>
            <aop:after-throwing method="afterThrowing" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:after-throwing>
            <aop:after method="after" pointcut="execution(public void com.xiaobo.aop.Target.save())"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

切点表达式的抽取

image-20210206161621054

applicationconfig配置文件

<?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 id="target" class="com.xiaobo.aop.Target"></bean>
    <!--切面对象-->
    <bean id="myAspect" class="com.xiaobo.aop.MyAspect"></bean>
​
    <!--配置织入 告诉Spring框架 那些方法(切点)需要进行哪些增强(前置增强、后置增强)-->
    <aop:config>
        <!--声明切面-->
        <aop:aspect ref="myAspect">
            <!--切面:切点+通知-->
            <!--抽取切点表达式-->
            <aop:pointcut id="myPointcut" expression="execution(* com.xiaobo.aop.*.*(..))"></aop:pointcut> 
            <aop:around method="around" pointcut-ref="myPointcut"/>
            <aop:after method="after" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

知识点总结

image-20210206162356829

4.4、基于注解的AOP开发

image-20210206162605776

1、创建目标接口和目标类

package com.xiaobo.anno;
​
public interface TargetInterface {
    public void save();
}
package com.xiaobo.anno;
​
​
import org.springframework.stereotype.Component;
​
@Component("target")
public class Target implements TargetInterface {
​
    @Override
    public void save() {
​
        System.out.println("小波实现了");
        //创造异常
        //int i=1/0;
    }
}

2、创建切面类

package com.xiaobo.anno;
​
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
​
@Component("myAspect")
@Aspect //标注当前类为一个切面类
public class MyAspect {
​
    //将切面配置织入关系
    //配置前置通知
    @Before("execution(* com.xiaobo.anno.*.*(..))")
    public void before(){
        System.out.println("前置增强");
    }
​
    public void afterReturning(){
        System.out.println("后置增强...");
    }
    //Proceeding JoinPoint: 正在执行的连接点===切点
    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("最终增强....");
    }
}

3、4均在上述注解中

5、配置文件中开启自动扫描和代理

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
      <!--组件扫描-->
      <context:component-scan base-package="com.xiaobo.anno"></context:component-scan>
      
     <!--自动代理-->
     <aop:aspectj-autoproxy/>
</beans>

知识要点总结

image-20210206164129323

问题一:何为AOP、它的作用具体是干什么的


标题:Spring基础学习——4.Spring的AOP简介
作者:xiaob0
地址:https://xiaobo.net.cn/articles/2021/02/05/1612531329171.html