04-Spring中的AOP编程之基于xml开发

AOP编程

​ AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

​ 学习AOP之后,可以在不修改源码的情况下,进行源码的增强业务,进行权限的校验,日志记录,性能监控,事务控制等。

Spring底层的AOP原理

  • 动态代理(静态代理)

    • JDK动态代理: 面向接口的,只能对实现了接口的类产生代理
    • Cglib动态代理(类似于JavaSsit第三方代理技术):对没有实现接口的类产生代理对象(生成子类对象)
  • 类实现了接口,Spring就用JDK动态代理,没有实现接口的,用Cglib动态代理,Spring底层可以自动切换

Spring的AOP开发入门(1)(基于XML开发)

1. 引入基本开发包和AOP开发相关的包

第一个aop联盟

第二个aspectj的依赖

第三个AOP核心包

第四个Spring与aspects整合的包

2. 引入xml配置约束文件

写切面的约束:aspect.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"> 
    <!--切面编程配置-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p1" expression="execution(* com.yd.service.impl.UserServiceImpl.add(..))"/>
        <!--配置切面类-->
        <aop:aspect ref="myAspect">
            <aop:before method="log" pointcut-ref="p1"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>

写spring扫描类文件,管理相关类的对象:spring.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" 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"> <!-- bean definitions here -->

    <context:component-scan base-package="com.yd.service"></context:component-scan>
    <context:component-scan base-package="com.yd.aspect"></context:component-scan>

</beans>

3. 编写原本的代码(切入点)

UserService:

public interface UserService {
    //添加用户方法
    public void add();
}

接口的实现类UserServiceImpl:

  • 使用@Service将该类交由spring容器管理
@Service
public class UserServiceImpl implements UserService {

    @Override
    public void add(){
        System.out.println("添加用户信息...");
    }
}

4. 编写增强类(通知)

  • 使用@Component将该类交由spring容器管理
@Component
public class MyAspect {
    public void log(){
        System.out.println("添加日志");
    }
}

5. 运行测试代码

public class Demo {

    @Test
    public void run(){
        //引入配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext( "spring.xml","aspect.xml");
        //从spring容器中获取对象
        UserService userService = (UserService)ac.getBean("userServiceImpl");
        //执行对象方法
        userService.add();
    }

}

运行结果:

Spring的AOP开发入门(2)(基于XML开发)

UserService:

public interface UserService {
    public void add();
    public void delete();
    public String deleteReturn();
    public void deleteAround();
    public void update(String uname,int pwd);
    public String updateReturn(String uname,int pwd);
    public void selectException();
    public void selectFin();
}

实现类UserServiceImpl:

@Service
public class UserServiceImpl implements UserService {

    @Override
    public void add(){
        System.out.println("添加用户信息...");
    }

    @Override
    public void delete() {
        System.out.println("删除用户信息...");
    }
    @Override
    public String deleteReturn() {
        System.out.println("删除用户,有返回值...");
        return "123";
    }
    @Override
    public void deleteAround(){
        System.out.println("删除信息deleteAround...");
    }

    @Override
    public void update(String uname,int pwd) {
        System.out.println("uname:"+uname+" pwd:"+pwd);
    }

    @Override
    public String updateReturn(String uname,int pwd) {
        System.out.println("uname:"+uname+" pwd:"+pwd);
        return uname;
    }

    @Override
    public void selectException() {
        System.out.println("select异常。。。");
        System.out.println(1/0);
        System.out.println("select2。。。");
    }

    @Override
    public void selectFin() {
        System.out.println("select无异常。。。");

    }

}

增强类MyAspect:

@Component
public class MyAspect {

    public void check(){
        System.out.println("----之前校验身份");
    }

    public void back(){
        System.out.println("----之后增强");
    }

    /**
     * 接收原方法返回值的后置增强方法
     * @param obj 切入点的返回值
     */
    public void backReturn(Object obj){
        System.out.println("后置接收切入点返回值:"+obj);
    }

    /**
     * 环绕增强
     * @param point 连接点
     * @throws Throwable
     */
    public void around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("----之前增强");
        //执行切入点的方法
        point.proceed();
        System.out.println("----之后增强");
    }

    /**
     * 环绕增强,接收切入点的传入的参数
     * @param point
     * @throws Throwable
     */
    public void aroundParam(ProceedingJoinPoint point)throws Throwable{
        System.out.println("---之前增强");
        //获取切入点的参数
        Object[] args = point.getArgs();
        point.proceed();
        System.out.println("---之后增强 切入点参数1:"+args[0]+" 参数2:"+args[1]);
    }
    /**
     * 环绕增强,接收切入点的传入的参数,切接收返回
     * @param point
     * @throws Throwable
     */
    public void aroundReturn(ProceedingJoinPoint point)throws Throwable{
        System.out.println("---之前增强");
        //获取切入点的参数
        Object[] args = point.getArgs();
        String str = (String)point.proceed();
        System.out.println("---之后增强 切入点参数1:"+args[0]+" 参数2:"+args[1]+" 返回值:"+str);
    }

    /**
     * 切入点有异常
     * @param e 异常
     */
    public void afterCatch(Exception e){
        System.out.println(e.getMessage());
        System.out.println("---捕获异常");
    }

    public void finallyDo(){
        System.out.println("finally,总会执行...");
    }
}

AOP配置文件:

<?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">
    <!--切面编程配置-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="p1" expression="execution(* com.yd.service.impl.UserServiceImpl.add(..))"/>
        <aop:pointcut id="p2" expression="execution(* com.yd.service.impl.UserServiceImpl.delete(..))"/>
        <aop:pointcut id="p3" expression="execution(* com.yd.service.impl.UserServiceImpl.deleteReturn(..))"/>
        <aop:pointcut id="p4" expression="execution(* com.yd.service.impl.UserServiceImpl.deleteAround(..))"/>
        <aop:pointcut id="p5" expression="execution(* com.yd.service.impl.UserServiceImpl.update(..))"/>
        <aop:pointcut id="p6" expression="execution(* com.yd.service.impl.UserServiceImpl.updateReturn(..))"/>
        <aop:pointcut id="p7" expression="execution(* com.yd.service.impl.UserServiceImpl.selectException(..))"/>
        <aop:pointcut id="p8" expression="execution(* com.yd.service.impl.UserServiceImpl.selectFin(..))"/>



        <!--配置切面类-->
        <aop:aspect ref="myAspect">
            <!-- 之前增强-->
            <aop:before method="check" pointcut-ref="p1"></aop:before>
            <!-- 之后增强-->
            <aop:after-returning method="back" pointcut-ref="p2"></aop:after-returning>
            <!-- 之后增强接收切入点返回值  obj:增强方法接收返回值的参数,必须与方法中参数名一致-->
            <aop:after-returning method="backReturn" pointcut-ref="p3" returning="obj"></aop:after-returning>
            <!-- 环绕增强-->
            <aop:around method="around" pointcut-ref="p4"></aop:around>
            <!-- 环绕增强,获取切入点传入的参数信息-->
            <aop:around method="aroundParam" pointcut-ref="p5"></aop:around>
            <!-- 环绕增强,获取切入点传入的参数信息,且有返回-->
            <aop:around method="aroundReturn" pointcut-ref="p6"></aop:around>

            <!-- 最终通知,有无异常都会执行,相当于finally-->
            <aop:after method="finallyDo" pointcut-ref="p7"></aop:after>

            <!-- 切入点有异常,后置增强捕获 throwing="e"异常参数,必须与方法中一致-->
            <aop:after-throwing method="afterCatch" pointcut-ref="p7" throwing="e"></aop:after-throwing>

            <aop:after method="finallyDo" pointcut-ref="p8"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

测试类:

public class Demo {

    @Test
    public void run(){
        ApplicationContext ac = new ClassPathXmlApplicationContext( "spring.xml","aspect.xml");
        UserService userService = (UserService)ac.getBean("userServiceImpl");
        //userService.add();
        //userService.delete();
        //userService.deleteReturn();
        //userService.deleteAround();
        //userService.update("张三",1234);
        //userService.updateReturn("李四",121);
        //userService.selectException();
        userService.selectFin();
    }
  • 注意:最终通知after和后置异常通知after-throwing的顺序不同,打印结果顺序不同

方式一:

运行结果

方式二:

运行结果:

切入点表达式语法

基于execution的函数完成的

语法

  • execution([访问修饰符] 方法返回值 包名.类名.方法名(参数))

com.spring.service.UserServiceImpl.add(..) 一般情况最好将方法名写完整

com.spring.service.UserServiceImpl.*(..) 开发中用的最多的是这种,对当前类下所有的方法做增强处理(场景:事务处理)

com.spring.service.impl.save(..)

com.spring.service.impl.*(..) 表示: com.spring.service.impl类下所有方法被增强

* *.*service.impl.add(..)没有包可以用*代替

* com.spring..(..)表示com.spring包下所有的类,所有方法都被增强

原文地址:https://www.cnblogs.com/soft-test/p/14905374.html