Spring AOP之简单实践

Spring AOP建立在代理之上,所以先对代理有个简单的认识也是很有必要的,下面结合代码来进行简要说明。

1,首先定义一个接口和实体对象

public class Student {
    public String name ;
    public int age ;
}
public interface IStudentService {
    /**
     * 添加学生
     * */
    void addStudent(Student student) ;
    /**
     * 删除学生
     * */
    void removeStudent(String studentId) ; 
}
public class DefaultStudentService implements IStudentService {
    @Override
    public void addStudent(Student student) {
        System.out.println("新增学生信息");
    }
    @Override
    public void removeStudent(String studentId) {
        System.out.println("删除ID为" + studentId+"的学生信息");
    }
}

2,Java的动态代理技术

Java的动态代理主要涉及到下面两个类型
1)java.lang.reflect.InvocationHandler接口

/**
代理实例的调用处理程序实现的接口;
每个代理实例都有一个关联的调用处理程序。
在代理实例上调用方法时,方法调用将被处理并发送到其调用处理程序的invoke方法。
*/
public interface InvocationHandler {
    /**
            @param proxy 动态生成的代理对象实例
            @param method 被代理对象调用的方法
            @param args 被调用的方法的参数
            @return 从代理实例上的方法调用返回的值,其类型必须和被代理接口中所定义的返回类型兼容。
    */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

2)java.lang.reflect.Proxy对象

简单的说,Java动态代理就是通过Java的Proxy对象来创建某个实例对象的代理对象,在调用代理对象的时候便会触发调用InvocationHandler的invoke方法,我们在invoke方法中可以添加一些额外的代码来扩充能力,同时在invoke中我们可以判断哪个方法被调用,然后通过反射执行被代理对象上的这个方法。

3,使用Java动态代理实例

/**
     * Java的动态代理技术【代理整个接口类】
     */
    public static void javaDyncProxy() {
        // 要被代理的目标对象
        DefaultStudentService studentService = new DefaultStudentService();
        // 代理的调用处理器【当我们通过动态代理对象调用任何一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用】
        StudentServiceInvocationHandler invocationHandler = new StudentServiceInvocationHandler(studentService);
        // 创建代理对象
        IStudentService service = (IStudentService)Proxy.newProxyInstance(studentService.getClass().getClassLoader(),
                studentService.getClass().getInterfaces(), invocationHandler);
        service.addStudent(new Student());
    }
    public static class StudentServiceInvocationHandler implements InvocationHandler {
        private IStudentService target;
        public StudentServiceInvocationHandler(IStudentService studentService) {
            this.target = studentService;
        }

        /*
         * @param proxy
         * 真实对象的真实代理对象;InvocationHandler本身,例如这里的:StudentServiceInvocationHandler
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("是的,你已经是在使用Proxy了");
            return method.invoke(target, args);
        }
    }
    public static void main(String[] args) {
         javaDyncProxy() ;
    }

执行main方法后,得到的打印输入如下

是的,你已经是在使用Proxy了
新增学生信息

4,Spring AOP

前面的文章中有介绍过Spring AOP中的一些概念,其中包括Advice和Pointcut。 Pointcut用于筛选类和方法,而Advice负责确实执行点,通过两则的结合就有了Advisor(切面)。

我们先看下SpringAOP中这些对象的关系。

Spring AOP之简单实践

由上图可知
1)Pointcut接口依赖于ClassFilter和MethodMatcher两个接口,通过这两个接口来达到筛选类和方法的目的
2)Advice接口【是个Tag Interface】包含了众多的子接口,通过子接口来扩展其功能,每个子接口都分别代表不同的方法执行点(内部的抽象方法便是添加增强代码的地方)
3)Adisor接口依赖于Advice接口,代表一个类中的所有方法的某些执行点,其最常用的子接口类型PointcutAdvisor有添加了对Pointcut接口的依赖,表示某些类中某些方法的某些执行点

下面我们更进一步的看看各个接口都有哪些实现

Pointcut实现类关系图

Spring AOP之简单实践

Advice接口关系图

Spring AOP之简单实践

ThrowsAdvice是一个Tag interface,实现类具有以下任意一个或多个方法实现均可:
public void afterThrowing(Exception ex)
public void afterThrowing(RemoteException)
public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

Advisor关系图

Spring AOP之简单实践

上面通过类图展现了SpringAOP中几个关键概念间的关系,下面再看看SpringProxy的类图

Spring AOP之简单实践

1)ProxyCreatorSupport与AopProxyFactory关联,在内部默认创建DefaultAopProxyFactory对象

2)AopProxyFactory依赖AopProxy接口,AopProxy的实现类包含了基于Java动态代理的JdkDynamicAopProxy和基于cglib的CglibAopProxy对象

3)我们在使用AopProxy的时候,内部会根据我们的设置来动态的选择使用Java动态代理还是基于cglib的代理。

下面通过示例代码来说明Spring Aop的以上这些对象

使用ProxyFactory
/**
 * 定义“方位”以及对应的增强代码。
 * 使用时,如果没提供具体的Ponitcut,该增强会织入到目标类的所有方法上。
 * */
public class StudentServiceAdvice implements MethodBeforeAdvice, AfterReturningAdvice,ThrowsAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("调用方法" + method.getName() +"前");

    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("调用方法" + method.getName() +"返回后");
    }

    /**
     * 方法名必须是afterThrowing,前三个参数是可选【同时都出现或都不出现】,最后个参数不行是Throwable或子类。
     * 可以定义多个afterThrowing方法,Spring会自动选用最匹配的增强方法。
     * */
    public void afterThrowing(Method method, Object[] args, Object target,RuntimeException e) {
        System.out.println("调用方法" + method.getName() +"抛出异常后");
    }
}
/**
     * 只用增强应用到类上的所有方法上
     */
    public static void springProxy() {
        // 要被代理的目标对象
        DefaultStudentService studentService = new DefaultStudentService();
        /*
         * 代理工厂根据代理配置在内部使用AopProxy类型的代理创建代理对象,AopProxy的实现类有以下两个: 
         * 1)JdkDynamicAopProxy :基于Java的动态代理技术 
         * 2)Cglib2AopProxy : 基于CGLib的动态代理技术
         * 在使用ProxyFactory的时候,如果通过setInterface()方法指定目标接口进行代理,则使用JdkDynamicAopProxy;
         * 如果针对类的代理或者设置SetOptimize(true),则使用Cglib2AopProxy;
         */
        ProxyFactory factory = new ProxyFactory();
        // 设置要被代理的接口类型
        factory.setInterfaces(studentService.getClass().getInterfaces());
        // 设置代理的目标对象
        factory.setTarget(studentService);
        // 为代理目标添加增强[Advice包含了横切代码和连接点信息,所以本身就是一个简单的切面]
        factory.addAdvice(new StudentServiceAdvice());
        // 生成代理实例
        IStudentService proxy = (IStudentService) factory.getProxy();
        // 调用方法
        proxy.addStudent(new Student("test", 22));
        proxy.removeStudent("10001");
    }
执行后的输出结果:
调用方法addStudent前
新增学生信息
调用方法addStudent返回后
调用方法removeStudent前
删除ID为10001的学生信息
调用方法removeStudent返回后
使用AspectJProxyFactory
        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.4</version>
        </dependency>
@Aspect
public class CommAspect {

    /**
     * 前置增强
     * 所有目标类中的所有addStudent方法
     * */
    @Before("execution (* addStudent(..))")
    public void defore(JoinPoint joinPoint) {
        System.out.println(">>>>befor addStudent");
    }
}

public static void springAspectProxy() {
        // 要被代理的目标对象
        DefaultStudentService studentService = new DefaultStudentService();
        // 基于AspectJ的代理工厂
        AspectJProxyFactory factory = new AspectJProxyFactory();
        // 设置代理目标
        factory.setTarget(studentService);
        // 添加切面类
        factory.addAspect(CommAspect.class);
        // 生成代理实例
        IStudentService proxy = (IStudentService) factory.getProxy();
        // 调用方法
        proxy.addStudent(new Student("test", 22));
        proxy.removeStudent("10001");
    }

执行后输出:

>>>>befor addStudent
新增学生信息
删除ID为10001的学生信息

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原理介绍,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。传统事务中回滚点的使...
今天小编给大家分享的是一文解析spring中事务的传播机制,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区别,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。Spring Cloud Netfli...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。第一步:整合pom文件,在S...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。List 坑列表 = new ArrayList(2);...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇...
本篇内容主要讲解“Spring中的@Autowired和@Resource注解怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学...
今天小编给大家分享一下SpringSecurity怎么定义多个过滤器链的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家
这篇文章主要介绍“Spring的@Conditional注解怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring的@Con...
这篇文章主要介绍了SpringCloudGateway的熔断限流怎么配置的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringCloud&nb...
今天小编给大家分享一下怎么使用Spring解决循环依赖问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考
这篇文章主要介绍“Spring事务及传播机制的原理及应用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Sp...
这篇“SpringCloudAlibaba框架实例应用分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价
本篇内容主要讲解“SpringBoot中怎么使用SpringMVC”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习...
这篇文章主要介绍“SpringMVC适配器模式作用范围是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringMVC
这篇“导入SpringCloud依赖失败如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要讲解了“SpringMVC核心DispatcherServlet处理流程是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来
今天小编给大家分享一下SpringMVCHttpMessageConverter消息转换器怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以...
这篇文章主要介绍“Spring框架实现依赖注入的原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring框架...
本篇内容介绍了“Spring单元测试控制Bean注入的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下