Spring AOP

AOP

  • 面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

一些概念:

概念描述
连接点类中需要增强的方法
切入点实际被真正增强的方法
通知(增强)向切点动态添加代码
切面切点+通知

AOP 实现

AOP 底层使用动态代理:

  • JDK 动态代理(有接口时使用)
  • CGLIB 动态代理(无接口使用)

JDK 动态代理

创建接口实现类代理对象,增强类的方法

1、定义一个接口

public interface HelloWorld {
    public void sayHelloWorld();
}

2、实现接口

public class HelloWorldImpl implements HelloWorld {

    @Override
    public void sayHelloWorld() {
        System.out.println("Hello World");
    }
}

3、动态代理绑定和代理逻辑的实现

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyExample implements InvocationHandler {

    //真实对象
    private Object target = null;

    /**
     * 建立代理对象和真实对象的代理关系,并返回代理对象
     * @param target 真实对象
     * @return 代理对象
     */
    public Object bind(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
     * 代理方法逻辑
     * @param proxy 代理对象
     * @param method 当前调度方法
     * @param args 当前方法参数
     * @return 代理返回结果
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑方法");
        System.out.println("在调度真是对象之前的服务");
        //相当于sayHelloWorld()
        Object obj = method.invoke(target, args);
        System.out.println("在调度真是对象之后的服务");
        return obj;
    }
}

4、测试JDK动态代理

public class TestJdkProxy {

    public static void main(String[] args) {
        JdkProxyExample jdk = new JdkProxyExample();
        HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
        proxy.sayHelloWorld();
    }
}

5、测试结果:

进入代理逻辑方法
在调度真是对象之前的服务
Hello World
在调度真是对象之后的服务

CGLIB 动态代理

创建子类的代理对象,增强类的方法
1、创建一个非抽象的、也没有实现接口的类

public class SayHelloImpl {
    public void sayHello(String name) {
        System.out.println("hello "+name);
    }
}

2、CGLIB 动态代理


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyExample implements MethodInterceptor {

    /**
     * 生成 CGLIB 代理对象
     * @param cls Class 类
     * @return Class 类的 CGLIB 代理对象
     */
    public Object getProxy(Class cls) {
        //CGLIB enhancer 增强类对象
        Enhancer enhancer = new Enhancer();
        //设置超类地的类型
        enhancer.setSuperclass(cls);
        //定义代理逻辑对象为当前对象,要求当前对象实现 MethodInterceptor 方法
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }

    /**
     * 代理逻辑方法
     * @param proxy 代理对象
     * @param method 方法
     * @param args 方法参数
     * @param methodProxy 方法代理
     * @return 代理逻辑返回
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.err.println("调用真实对象前....");
        //CGLIB 反射调用真实对象方法
        Object result = methodProxy.invokeSuper(proxy, args);
        System.err.println("调用真实对象后....");
        return result;
    }
}

3、测试 CGLIB 动态代理

public class TestCglibProxy {

    public static void main(String[] args) {
        CglibProxyExample cglib = new CglibProxyExample();
        SayHelloImpl proxyObj = (SayHelloImpl) cglib.getProxy(SayHelloImpl.class);
        proxyObj.sayHello("小明");
    }
}

4、测试结果:

调用真实对象前....
hello 小明
调用真实对象后....

开发 Spring AOP

新建一个maven工程,并引入依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.6</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

下面我们分别用xml和注解的方式来演示下aop的使用。

使用@AspectJ注解开发 Spring AOP

后面代码中用到的注解:

注解说明
@Before在被代理对象的方法之前调用,前置通知
@Around将被代理对象的方法封装起来,用环绕的方式取代它,可通过反射调用原有方法
@After在被代理对象的方法之后调用,后置通知
@AfterReturning在被代理对象的方法正常返回后调用,返回通知
@AfterThrowing在被代理对象的方法抛出异常后调用,异常通知

简单说下切点表达式:
比如:execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..))

  • execution:表示执行方法时会触发
  • *:代表任意返回类型的方法
  • top.wushanghui.aop.annotation.service.impl.RoleServiceImppl:代表类的全类名
  • printRole:被拦截的方法名
  • (..):表示任意参数

Role

public class Role {

    private Long id;
    private String roleName;
    private String note;

    public Role(Long id, String roleName, String note) {
        this.id = id;
        this.roleName = roleName;
        this.note = note;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", note='" + note + '\'' +
                '}';
    }
}

RoleService 接口

package top.wushanghui.aop.annotation.service;

import top.wushanghui.aop.annotation.pojo.Role;

public interface RoleService {

    public void printRole(Role role, int sort);
}

RoleServiceImppl 实现类

package top.wushanghui.aop.annotation.service.impl;

import org.springframework.stereotype.Component;
import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.service.RoleService;

@Component
public class RoleServiceImppl implements RoleService {

    @Override
    public void printRole(Role role, int sort) {
        System.out.println("{id = " + role.getId() + ", roleName = " + role.getRoleName() + ", note = " + role.getNote() + "}");
        System.out.println("sort" + sort);
    }
}

RoleVerifier 接口

package top.wushanghui.aop.annotation.verifier;

import top.wushanghui.aop.annotation.pojo.Role;

public interface RoleVerifier {

    public boolean verify(Role role);
}

RoleVerifierImpl 实现类

package top.wushanghui.aop.annotation.verifier.impl;

import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.verifier.RoleVerifier;

public class RoleVerifierImpl implements RoleVerifier {
    @Override
    public boolean verify(Role role) {
        return role != null;
    }
}

RoleAspect 切面类

package top.wushanghui.aop.annotation.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.service.impl.RoleServiceImppl;
import top.wushanghui.aop.annotation.verifier.RoleVerifier;
import top.wushanghui.aop.annotation.verifier.impl.RoleVerifierImpl;

@Aspect
public class RoleAspect {

    @DeclareParents(value = "top.wushanghui.aop.annotation.service.impl.RoleServiceImppl+", defaultImpl = RoleVerifierImpl.class)
    private RoleVerifier roleVerifier;

    @Pointcut("execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..))")
    public void print() {

    }

    @Before("execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..)) && args(role, sort)")
    public void before(Role role, int sort) {
        System.out.println("before ... role: " + role + ", sort: " + sort);
    }

    @After("print()")
    public void after() {
        System.out.println("after ... ");
    }

    @AfterReturning("print())")
    public void afterReturning() {
        System.out.println("afterReturning ... ");
    }

    @AfterThrowing("print()")
    public void afterThrowing() {
        System.out.println("afterThrowing ... ");
    }

    @Around("print()")
    public void around(ProceedingJoinPoint joinPoint) {
        System.out.println("around before ... ");
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after ... ");
    }
}

AopConfig 配置类

package top.wushanghui.aop.annotation.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import top.wushanghui.aop.annotation.aspect.RoleAspect;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("top.wushanghui.aop.annotation")
public class AopConfig {

    @Bean
    public RoleAspect getRoleAspect() {
        return new RoleAspect();
    }
}

测试:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
        RoleService roleService = ctx.getBean(RoleService.class);
        Role role = new Role(1L, "admin", "note1");
        RoleVerifier roleVerifier = (RoleVerifier) roleService;
        if (roleVerifier.verify(role)) {
            roleService.printRole(role, 2);
        }
        System.out.println("============================");
        // 测试异常通知
        role = null;
        if (roleVerifier.verify(role)) {
            roleService.printRole(role, 2);
        }
        System.out.println("============================");
    }
}

结果:

around before ... 
before ... role: Role{id=1, roleName='admin', note='note1'}, sort: 2
{id = 1, roleName = admin, note = note1}
sort2
afterReturning ... 
after ... 
around after ... 
============================
============================

多个切面

MultiBean 接口

package top.wushanghui.multi.bean;

public interface MultiBean {

    public void testMulti();
}

MultiBeanImpl 实现类

package top.wushanghui.multi.bean.impl;

import org.springframework.stereotype.Component;
import top.wushanghui.multi.bean.MultiBean;

@Component
public class MultiBeanImpl implements MultiBean {
    @Override
    public void testMulti() {
        System.out.println("测试多个切面!");
    }
}

三个切面

package top.wushanghui.multi.aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;

@Aspect
@Order(2)
public class Aspect1 {

    @Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
    public void print() {

    }

    @Before("print()")
    public void before() {
        System.out.println("before 1 ... ");
    }

    @After("print()")
    public void after() {
        System.out.println("after 1 ... ");
    }

    @AfterReturning("print())")
    public void afterReturning() {
        System.out.println("afterReturning 1 ... ");
    }

    @AfterThrowing("print()")
    public void afterThrowing() {
        System.out.println("afterThrowing 1 ... ");
    }
}

package top.wushanghui.multi.aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;

@Aspect
@Order(1)
public class Aspect2 {

    @Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
    public void print() {

    }

    @Before("print()")
    public void before() {
        System.out.println("before 2 ... ");
    }

    @After("print()")
    public void after() {
        System.out.println("after 2 ... ");
    }

    @AfterReturning("print())")
    public void afterReturning() {
        System.out.println("afterReturning 2 ... ");
    }

    @AfterThrowing("print()")
    public void afterThrowing() {
        System.out.println("afterThrowing 2 ... ");
    }
}

package top.wushanghui.multi.aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;

@Aspect
@Order(3)
public class Aspect3 {

    @Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
    public void print() {

    }

    @Before("print()")
    public void before() {
        System.out.println("before 3 ... ");
    }

    @After("print()")
    public void after() {
        System.out.println("after 3 ... ");
    }

    @AfterReturning("print())")
    public void afterReturning() {
        System.out.println("afterReturning 3 ... ");
    }

    @AfterThrowing("print()")
    public void afterThrowing() {
        System.out.println("afterThrowing 3 ... ");
    }
}

MultiConfig 配置类

package top.wushanghui.multi.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import top.wushanghui.multi.aspect.Aspect1;
import top.wushanghui.multi.aspect.Aspect2;
import top.wushanghui.multi.aspect.Aspect3;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("top.wushanghui.multi")
public class MultiConfig {

    @Bean
    public Aspect1 getAspect1() {
        return new Aspect1();
    }

    @Bean
    public Aspect2 getAspect2() {
        return new Aspect2();
    }

    @Bean
    public Aspect3 getAspect3() {
        return new Aspect3();
    }
}

测试:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(MultiConfig.class);
        MultiBean multiBean = ctx.getBean(MultiBean.class);
        multiBean.testMulti();
    }
}

结果:

before 2 ... 
before 1 ... 
before 3 ... 
测试多个切面!
afterReturning 3 ... 
after 3 ... 
afterReturning 1 ... 
after 1 ... 
afterReturning 2 ... 
after 2 ... 

使用 XML 配置开发Spring AOP

xml 配置AOP元素

AOP配置元素说明
aop:config顶层的AOP配置元素,它是aop配置的开始
aop:aspect定义一个切面
aop:pointcut定义切点
aop:before定义前置通知
aop:after定义后置通知
aop:after-returning定义返回通知
aop:after-throwing定义异常通知
aop:around定义环绕方式
aop:declare-parents给通知引入新的额外接口,增强功能

实体类 Role

package top.wushanghui.aop.xml.pojo;

public class Role {

    private Long id;
    private String roleName;
    private String note;

    public Role(Long id, String roleName, String note) {
        this.id = id;
        this.roleName = roleName;
        this.note = note;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", roleName='" + roleName + '\'' +
                ", note='" + note + '\'' +
                '}';
    }
}

RoleService 接口

package top.wushanghui.aop.xml.service;

import top.wushanghui.aop.xml.pojo.Role;

public interface RoleService {

    public void printRole(Role role, int sort);
}

RoleServiceImppl 实现类

package top.wushanghui.aop.xml.service.impl;

import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.service.RoleService;

public class RoleServiceImppl implements RoleService {

    @Override
    public void printRole(Role role, int sort) {
        System.out.println("{id = " + role.getId() + ", roleName = " + role.getRoleName() + ", note = " + role.getNote() + "}");
        System.out.println("sort" + sort);
    }
}

RoleVerifier 接口
用来检测角色是否为空,后面会有它的实现类

package top.wushanghui.aop.xml.verifier;

import top.wushanghui.aop.xml.pojo.Role;

public interface RoleVerifier {

    public boolean verify(Role role);
}

RoleVerifierImpl 实现类

package top.wushanghui.aop.xml.verifier.impl;

import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.verifier.RoleVerifier;

public class RoleVerifierImpl implements RoleVerifier {
    @Override
    public boolean verify(Role role) {
        return role != null;
    }
}

XmlAspect 这时一个切面类

package top.wushanghui.aop.xml.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.verifier.RoleVerifier;

public class XmlAspect {

    private RoleVerifier roleVerifier;

    public void before(Role role, int sort) {
        System.out.println("before ... role: " + role + ", sort: " + sort);
    }

    public void after() {
        System.out.println("after ... ");
    }

    public void afterReturning() {
        System.out.println("afterReturning ... ");
    }

    public void afterThrowing() {
        System.out.println("afterThrowing ... ");
    }

    public void around(ProceedingJoinPoint joinPoint) {
        System.out.println("around before ... ");
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after ... ");
    }
}

spring-aop.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 http://www.springframework.org/schema/beans/spring-beans.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="xmlAspect" class="top.wushanghui.aop.xml.aspect.XmlAspect"/>
    <bean id="roleService" class="top.wushanghui.aop.xml.service.impl.RoleServiceImppl"/>
    <bean id="roleVerifier" class="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>

    <aop:config>
        <!--引用xmlAspect作为切面-->
        <aop:aspect ref="xmlAspect">
            <!--定义切点-->
            <aop:pointcut id="print" expression="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..))"/>
            <aop:before method="before" pointcut="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..)) and args(role, sort)"/>
            <!--定义通知,引入切点-->
            <aop:after method="after" pointcut-ref="print"/>
            <aop:after-returning method="afterReturning" pointcut-ref="print"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="print"/>
            <aop:around method="around" pointcut-ref="print"/>
            <aop:declare-parents types-matching="top.wushanghui.aop.xml.service.impl.RoleServiceImppl+"
                                 implement-interface="top.wushanghui.aop.xml.verifier.RoleVerifier"
                                    default-impl="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>
        </aop:aspect>
        
    </aop:config>
</beans>

首先需要一些类注入到spring 容器中,

<bean id="xmlAspect" class="top.wushanghui.aop.xml.aspect.XmlAspect"/>
<bean id="roleService" class="top.wushanghui.aop.xml.service.impl.RoleServiceImppl"/>
<bean id="roleVerifier" class="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>

使用<aop:config>配置aop,首先引用切面<aop:aspect ref="xmlAspect">,大家可以看到我定义了一个公共的切点:

<aop:pointcut id="print" expression="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..))"/>

这样在五种通知中都可以引入,比如<aop:after method="after" pointcut-ref="print"/>后置通知中pointcut-ref="print",当然你也可以想before 前置通知中,自己定义切点,<aop:before method="before" pointcut="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..)) and args(role, sort)"/>
需要注意的是and args(role, sort)" 我们使用and args来获取参数。

测试:

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aop.xml");
        RoleService roleService = ctx.getBean(RoleService.class);
        Role role = new Role(2L, "admin", "note1");
        RoleVerifier roleVerifier = (RoleVerifier) roleService;
        if (roleVerifier.verify(role)) {
            roleService.printRole(role, 2);
        }
        System.out.println("============================");
        // 测试异常通知
        role = null;
        if (roleVerifier.verify(role)) {
            roleService.printRole(role, 2);
        }
        System.out.println("============================");
    }
}

结果:

before ... role: Role{id=2, roleName='admin', note='note1'}, sort: 2
around before ... 
{id = 2, roleName = admin, note = note1}
sort2
around after ... 
afterReturning ... 
after ... 
============================
============================

参考:<<Java EE互联网轻量级框架整合开发>>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值