基于代理类实现Spring AOP

目录

  • ProxyFactoryBean类介绍
  • 基于JDK动态代理的Spring  AOP实现
  • 基于CGLIB代理的Spring  AOP实现
  • Spring的通知类型

ProxyFactoryBean类

虽然直接使用代理就可以创建代理的实例,但需要自己写创建代理的方法,比如JDK动态代理:

 1     ........
 2     //创建代理方法,参数是目标接口的实例
 3     public Object createProxy(UserInterface user){
 4         this.user=user;   //初始化目标接口实例
 5
 6         ClassLoader classLoader=JdkProxy.class.getClassLoader();  //获取当前类的类加载器,当前类类名.class.getClassLoader()
 7         Class[] classArr=user.getClass().getInterfaces();  //获取目标接口实例实现的全部接口
 8
 9         //参数:当前类的类加载器,目标接口实例实现的所有接口,当前类的实例
10         return Proxy.newProxyInstance(classLoader,classArr,this);
11     }

CGLIB代理:

1     //创建代理,参数是Object类型
2     public Object createProxy(Object target){
3         Enhancer enhancer=new Enhancer();   //创建一个动态类对象
4         enhancer.setSuperclass(target.getClass());  //将这个动态类对象的父类/基类设置为目标类(需要增强的类)
5         enhancer.setCallback(this);  //设置回调
6         return  enhancer.create();  //返回创建的代理
7     }

什么乱七八糟的过程、方法,我哪记得住。ProxyFactoryBean类可解决此问题。

ProxyFactoryBean是FactoryBean接口的一个实现类,FactoryBean接口的作用是实例化一个Bean,ProxyFactoryBean类的作用实例化一个Bean的代理,我们在xml文件中配置代理即可,不必手写创建代理的方法。

基于JDK动态代理的Spring  AOP实现

1、新建包user,用于写被代理的类、接口。包下新建接口UserInterface

1 public interface UserInterface {
2     public void addUser();
3     public void alterUser();
4     public void deleteUser();
5 }

再新建一个实现类User

 1 public class User implements UserInterface {
 2     @Override
 3     public void addUser() {
 4         //模拟添加用户
 5         System.out.println("正在添加用户");
 6         System.out.println("添加用户成功");
 7     }
 8
 9     @Override
10     public void alterUser() {
11         //模拟修改用户信息
12         System.out.println("正在修改用户信息");
13         System.out.println("修改用户信息成功");
14     }
15
16     @Override
17     public void deleteUser() {
18         //模拟删除用户
19         System.out.println("正在删除用户");
20         System.out.println("删除用户成功");
21     }
22 }

2、新建包aspect,用来写切面类。包下新建类MyAspect,需实现MethodInterceptor接口,此接口是org.aopalliance.intercept包下的接口,不要import导入错了。(需要aopalliance.jar包的支持

 1 public class UserProxy implements MethodInterceptor {
 2     @Override
 3     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
 4         checkPermission();  //前增强
 5         Object object=methodInvocation.proceed();  //通过invoke()的参数调用
 6         log();  //后增强
 7         return object;
 8     }
 9
10     public void checkPermission(){
11         //模拟检查权限
12         System.out.println("正在检查权限");
13         System.out.println("权限已够");
14     }
15
16     public void log(){
17         //模拟记录日志
18         System.out.println("正在记录日志");
19         System.out.println("日志已记录");
20     }
21 }

当然,可以实现其它的接口(Spring的通知类型)。不同的接口,提供的功能不同。

3、在xml中配置代理

   <!-- 目标类-->
    <bean id="user" class="user.User" />

    <!-- 切面类-->
    <bean id="myAspect" class="aspect.MyAspect" />

    <!-- 这才是真正的代理类,class要指定为ProxyFactoryBean类-->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--指定接口,如果实现了多个接口,用子元素list来写-->
        <property name="proxyInterfaces" value="user.UserInterface" />
        <!--指定目标类的实例-->
        <property name="target" ref="user" />
        <!--指定切面类的id/name,只能用value,不能用ref-->
        <property name="interceptorNames" value="myAspect" />
        <!--指定使用的代理,proxyTargetClass是问是否代理类,JDK动态代理是代理接口,CGLIB代理是代理类。false即不是代理类,即使用JDK动态代理-->
        <!--默认就是false,JDK动态代理。此句配置可缺省-->
        <property name="proxyTargetClass" value="false" />
        <!--返回的代理类实例是否是单实例,默认为true,单实例。此句配置可缺省-->
        <property name="singleton" value="true" />
    </bean>

ProxyFactoryBean类已经写好了创建代理代码,这个类使用setter方法注入依赖,我们只需要用<property>注入它需要的参数即可。

4、新建包test,包下新建测试类Test

1 public class Test {
2     public static void main(String[] args) {
3         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
4         //因为使用的JDK动态代理,代理的是接口,所以要使用接口来声明
5         UserInterface user=applicationContext.getBean("userProxy", UserInterface.class);
6         user.addUser();
7     }
8 }

运行,控制台输出如下

正在检查权限
权限已够
正在添加用户
添加用户成功
正在记录日志
日志已记录

代理成功。

基于CGLIB代理的Spring  AOP实现

JDK动态代理代理的是接口,CGLIB代理的类,所以我们只需要把上例中有关接口的部分去掉即可。也可一步步从头开始。

1、新建包user,包下新建类User

 1 public class User{
 2     public void addUser() {
 3         //模拟添加用户
 4         System.out.println("正在添加用户");
 5         System.out.println("添加用户成功");
 6     }
 7
 8     public void alterUser() {
 9         //模拟修改用户信息
10         System.out.println("正在修改用户信息");
11         System.out.println("修改用户信息成功");
12     }
13
14     public void deleteUser() {
15         //模拟删除用户
16         System.out.println("正在删除用户");
17         System.out.println("删除用户成功");
18     }
19 }

2、新建包aspect,包下新建切面类MyAspect

 1 public class MyAspect implements MethodInterceptor {
 2     @Override
 3     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
 4         checkPermission();  //前增强
 5         Object object=methodInvocation.proceed();  //通过invoke()的参数调用
 6         log();  //后增强
 7         return object;
 8     }
 9
10     public void checkPermission(){
11         //模拟检查权限
12         System.out.println("正在检查权限");
13         System.out.println("权限已够");
14     }
15
16     public void log(){
17         //模拟记录日志
18         System.out.println("正在记录日志");
19         System.out.println("日志已记录");
20     }
21 }

3、在xml中配置代理

<!-- 目标类-->
    <bean id="user" class="user.User" />

    <!-- 切面类-->
    <bean id="myAspect" class="aspect.MyAspect" />

    <!-- 这才是真正的代理类-->
    <bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--指定目标类的实例-->
        <property name="target" ref="user" />
        <!--指定切面类的id/name,只能用value,不能用ref-->
        <property name="interceptorNames" value="myAspect" />
        <!--指定使用的代理,proxyTargetClass是问是否代理类,JDK动态代理是代理接口,CGLIB代理是代理类。false即不是代理类,即使用JDK动态代理-->
        <!--默认就是false,JDK动态代理。此句配置可缺省-->
        <property name="proxyTargetClass" value="false" />
        <!--返回的代理类实例是否是单实例,默认为true,单实例。此句配置可缺省-->
        <property name="singleton" value="true" />
    </bean>

去掉指定接口的那句配置就ok。

4、新建包test,包下新建测试类Test

1 public class Test {
2     public static void main(String[] args) {
3         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
4         //要使用目标类来声明
5         User user=applicationContext.getBean("userProxy", User.class);
6         user.addUser();
7     }
8 }

运行,控制台输出如下

正在检查权限
权限已够
正在添加用户
添加用户成功
正在记录日志
日志已记录

代理成功。

说明

需要2个包:spring-aop.jar,这个是Spring自带的,不用管。aopalliance.jar,如果使用了maven或IDEA的自动下载Spring所需的包,会自动添加这个包,不用管,如果是手动添加Spring需要的包,则还需要自己去下载、添加这个包。

Spring的通知类型

在例子的切面类中,我们实现的是MethodInterceptor接口,这个接口是环绕通知的接口,可在目标方法前后实施增强,可用于日志、事务管理等。

Spring的5种通知类型

 通知类型   对应接口   增强时间   常见应用  
环绕通知     MethodInterceptor     在目标方法执行前后实施增强       日志、事务处理    
前置通知 MethodBeforeAdvice 在目标方法执行前进行增强 权限管理
后置通知 AfterReturningAdvice 在目标方法执行后进行增强 关闭流、上传文件、删除临时文件等  
异常通知 ThrowsAdvice 在方法抛出异常后进行增强 处理异常、记录日志等
引介通知 IntroductionInterceptor    在目标类中添加一些新的属性、方法 修改旧版程序

可根据需要,选择实现接口。

Advice指的就是目标方法。增强其实就是做一些额外的处理。

原文地址:https://www.cnblogs.com/chy18883701161/p/11139169.html

时间: 2024-08-30 02:27:12

基于代理类实现Spring AOP的相关文章

Spring AOP(基于代理类的AOP实现)

#基于代理类的AOP实现:step1: 1 package com.sjl.factorybean; 2 /**切面类*/ 3 import org.aopalliance.intercept.MethodInterceptor; 4 import org.aopalliance.intercept.MethodInvocation; 5 6 public class MyAspect implements MethodInterceptor { 7 @Override 8 public Obj

CgLib动态代理学习【Spring AOP基础之一】

如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发现其参数类型是ClassLoader classLoader, Class<?>[] interface, InvocationHandler handler, 只支持根据接口实现代理类,如果所有代码都是自己掌控,当然没有问题.所有的业务逻辑均抽象出接口,然后所有的业务类实现接口,这样所有的业务类

代理模式 与 Spring AOP

AOP:在一个服务的流程中插入与业务逻辑无关的系统服务逻辑(例如Logging.Security),这样的逻辑称为Cross-cutting concerns,将Cross-cutting concerns独立出来设计为一个对象,这样的特殊对象称之为Aspect,Aspect-oriented programming着重在Aspect的设计上以及与应用程序的织入(Weave). 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把

java动态代理,及spring AOP

介绍:spring 的AOP (Aspect Oriented Programming)是通过java的动态代理来实现的,对于AOP不了解的朋友可以去网上看相关资料,我这里重点说明实现原理即java动态代理 要谈java动态代理就不得不说java的代理模式,我这里只给出代理模式的UML图 如图(1)及动态代理模式的UML类图 如图(2) 说明:图(2)中的红色红色斜体的类或接口是由java类库提供的即 Proxy和InvocationHandler 是java对动态代理的支持 图 (1) 和 图

Java动态代理学习【Spring AOP基础之一】

Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.lang.reflect.Proxy 首先从代码层面说明Java动态代理是如何实现的, 业务逻辑接口: /** * 创建一个人的接口,其中有一个吃的方法 */ public interface Person { public void eat(); } 创建一个实现该业务接口的类: /** * 人接口的

从代理模式到Spring AOP

什么是代理模式 假如我喜欢上隔壁班的翠花,但是我没胆量向她送花,这时候我需要一个铁杆哥们帮我做这件事, 很明显这哥们是个代理,是去执行任务的,但是花实际上是我"送"的,代理和我一样会送花这个动作,直接上代码. 1 public interface IProcess { 2 void SendFlower(); 3 } 1 public class Studnet1 implements IProcess { 2 3 @Override 4 public void SendFlower(

[转]彻底征服 Spring AOP 之 理论篇

基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, 含义总有着各种莫名其妙的差别. 鉴于此, 我在本章的开头, 着重为为大家介绍一个 Spring AOP 的各项术语的基本含义. 为了术语传达的准确性, 我在接下来的叙述中, 能使用英文术语的地方, 尽量使用英文. 什么是 AOP AOP(Aspect-Oriented Programming),

Spring实战(九)AOP概念以及Spring AOP

1.横切关注点(cross-cutting concern) 软件开发中,散布于应用中多处的功能被称为横切关注点,如事务.日志.安全. 横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑中),而把横切关注点和业务逻辑分离正是AOP要解决的问题. DI用于应用对象之间的解耦,AOP实现横切关注点与他们所影响的对象之间的解耦. 2.重用通用功能,最常见的技术是继承和委托 继承会导致脆弱的对象体系:委托可能需要对委托对象进行复杂的调用. 所以用切面取而代之. 3.AOP术

Spring AOP初步总结(一)

学习AOP有段时间了,一直没空总结一下,导致有些知识点都遗忘了,之后会把以前学过的Spring核心相关的知识点总结一轮... 先大体介绍下Spring AOP的特点(均摘自"Spring in action第四版"): Spring支持了AOP,另外还有很多实现了AOP的技术,例如AspectJ,它补充了Spring AOP框架的功能,他们之间有着大量的协作,而且Spring AOP中大量借鉴了AspectJ项目,Spring AOP相对粗粒度,而AspectJ提供更强大更细粒度的控制