0


Spring AOP实现 | 代理模式分析

在这里插入图片描述

💗wei_shuo的个人主页

💫wei_shuo的学习社区

🌐Hello World !

文章目录


Sping AOP

Spring AOP:

控制反转

AOP面向切面编程,通过

预编译

方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是

OOP

的延续,是软件开发中的一个热点,也是

Spring

框架中的一个重要内容,是

函数式编程

的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的

耦合度降低

,提高程序的可重用性,同时提高了开发的效率

在这里插入图片描述

代理模式

  • 代理模式是程序设计中的一种设计模式
  • 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源

代理模式分类:

  • 静态代理
  • 动态代理

优势:

  • 真实角色更加纯粹,不用关注公共业务
  • 公共业务交给代理角色,实现业务分工
  • 公共业务发生扩展时,方便集中管理

劣势:

  • 一个真实角色会产生一个代理,代码量会翻倍、效率降低

静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实代理:被代理的角色
  • 代理角色:代理真实角色
  • 客户:访问代理对象者
  • 接口
publicinterfaceRent{publicvoidrent();}
  • 真实角色
publicclassHost{publicvoidrent(){System.out.println("房东房子出租");}}
  • 代理角色
publicclassProxyimplementsRent{privateHost host;publicProxy(){}publicProxy(Host host){this.host = host;}publicvoidrent(){
        host.rent();}//看房publicvoidseeHouse(){System.out.println("中介带你看房");}//收中介费publicvoidmoney(){System.out.println("收中介费");}}
  • 客户端访问代理角色
publicclassClient{publicstaticvoidmain(String[] args){//创建房东对象Host host =newHost();//代理Proxy proxy =newProxy(host);//通过代理调用房东对象
        proxy.rent();}}

动态代理

动态代理:

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成
  • 动态代理是一个接口,对应一类业务
  • 动态代理可以代理多个类,只要实现一个接口

动态代理分类:

  • 基于接口——JDK动态代理
  • 基于类——cglib
  • Java字节码——Javasist

两种类了解:

  • Proxy——代理
  • InvocationHandl——调用处理程序

Proxy类:生成动态代理实例

  • Proxy创建动态代理类的实例提供了静态方法,也是所有动态代理类的父类的方法创建

方法:

//返回指定的代理实例的调用处理程序getInvocationHandler(Object proxy)//返回 java.lang.Class对象的代理类,给出了类装载器和一个阵列的接口getProxyClass(ClassLoader loader, 类<?>... interfaces)//如果指定的类是动态生成的可利用 getProxyClass法或代理类 newProxyInstance方法返回trueisProxyClass(类<?> cl)//返回指定的接口,将方法调用指定的调用处理程序的代理类的一个实例。 newProxyInstance(ClassLoader loader, 类<?>[] interfaces,InvocationHandler h)

InvocationHandl类:调用处理程序并返回结果

  • InvocationHandler是通过一个代理实例调用处理程序实现的接口。
  • 每个代理实例都有一个相关的调用处理程序。当一个方法是在一个代理实例调用,调用的方法进行编码并派遣其调用处理程序的invoke方法

方法:

//在代理实例上处理方法调用,并返回结果invoke(Object proxy, 方法 method,Object[] args)
  • proxy — 调用该方法的代理实例
  • method — 反射获取到的接口的方法
  • args — 使用此方法时传入的参数数组
  • ProxyInvocationHandler动态代理类
publicclassProxyInvocationHandlimplementsInvocationHandler{//被代理的接口privateObject target;publicvoidsetTarget(Object target){this.target = target;}//生成得到代理类publicObjectgetProxy(){//this.getClass().getClassLoader()  加载类所在位置//rent.getClass().getInterfaces()   表示代理接口//this    ==    InvocationHandler实现类returnProxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}//处理代理实例,并返回结果@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{//动态代理的本质,就是使用反射机制log(method.getName());Object result = method.invoke(target, args);return result;}publicvoidlog(String msg){System.out.println("执行了"+ msg +"方法");}}
  • Client客户类
publicclassClient{publicstaticvoidmain(String[] args){//真实角色:被代理的角色UserServiceImp userService =newUserServiceImp();//代理角色:代理真实角色ProxyInvocationHandl pih =newProxyInvocationHandl();//设置代理对象
        pih.setTarget(userService);//动态生成代理类UserService proxy =(UserService) pih.getProxy();

        proxy.query();}}/*
执行了query方法
[Debug]使用了query方法
查询用户
*/

AOP概述

提供声明式事物,允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是很切关注点,如:日志,安全,缓存,事物……
  • 切面(ASPECT):横切关注点被模块化的特殊对象。
  • 通知(Advice):切面必须要完成的工作。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的"地点"的定义。
  • 连接点(JoinPoint):与切入点匹配的执行点。

Spring实现AOP

方式一:使用Spring的API接口实现AOP

  • 使用AOP织入,需要导入一个依赖包
<dependencies><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency></dependencies>
  • applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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
        "></beans>
  • 前置Log日志类
publicclass log implementsMethodBeforeAdvice{//method:要执行的目标对象方法//object:参数//target:目标对象@Overridepublicvoidbefore(Method method,Object[] objects,Object target)throwsThrowable{System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");}}
  • 后置AfterLog类
publicclassAfterLogimplementsAfterReturningAdvice{//returnValue:返回值@OverridepublicvoidafterReturning(Object returnValue,Method method,Object[] objects,Object o1)throwsThrowable{System.out.println("执行了"+method.getName()+"放回结果为:"+returnValue);}}
  • UserService接口
publicinterfaceUserService{publicvoidadd();publicvoiddelete();publicvoidupdate();publicvoidselect();}
  • UserServiceImpl接口实现类
publicclassUserServiceImplimplementsUserService{publicvoidadd(){System.out.println("增加了一个用户");}publicvoiddelete(){System.out.println("删除了一个用户");}publicvoidupdate(){System.out.println("更新了一个用户");}publicvoidselect(){System.out.println("查询了一个用户");}}
  • 将UserServiceImpl接口实现类注册到Spring中,即applicationContext.xml中
<?xml version="1.0" encoding="UTF-8"?><beansxmlns="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--><beanid="userService"class="com.wei.service.UserServiceImpl"/><beanid="log"class="com.wei.log.log"/><beanid="agter"class="com.wei.log.AfterLog"/><!--方式一:使用原生的Spring API接口--><!--配置aop,需要导入aop的约束--><aop:config><!--切入点:
        execution:表达式
        execution(要执行的位置 * * * * *)
        --><aop:pointcutid="pointcut"expression="execution(* com.wei.service.UserServiceImpl.*(..))"/><!--执行环绕增强--><aop:advisoradvice-ref="log"pointcut-ref="pointcut"/><aop:advisoradvice-ref="agter"pointcut-ref="pointcut"/></aop:config></beans>
  • MyTest测试类
publicclassMyTest{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("applicationContext.xml");//动态代理的是接口UserService userService =(UserService) context.getBean("userService");
        userService.delete();}}/*
执行结果:
com.wei.service.UserServiceImpl的delete被执行了
删除了一个用户
执行了delete放回结果为:null
*/

方式二:自定义实现AOP

  • 自定义Diy类
publicclassDiyPointCut{publicvoidbefore(){System.out.println("===========方法执行前===========");}publicvoidafter(){System.out.println("===========方法执行后===========");}}
  • 将Diy类注册到Spring中,即applicationContext.xml中
<!--方式二:自定义类--><beanid="diy"class="com.wei.diy.DiyPointCut"/><aop:config><!--自定义切面:ref要引用的类--><aop:aspectref="diy"><!--切入点--><!--execution(修饰符返回值 类路径.*(..))--><aop:pointcutid="point"expression="execution(* com.wei.service.UserServiceImpl.*(..))"/><!--通知--><!--
          method="before"   自定义的方法名
          pointcut-ref="point"  方法执行在point切入点之后
        --><aop:beforemethod="before"pointcut-ref="point"/><aop:aftermethod="after"pointcut-ref="point"/></aop:aspect></aop:config>
  • MyTest测试类
publicclassMyTest{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("applicationContext.xml");//动态代理的是接口UserService userService =(UserService) context.getBean("userService");
        userService.delete();}}/*
===========方法执行前===========
删除了一个用户
===========方法执行后===========
*/
aop中execution 表达式(*execution(\* 包名.\*.*(..))*)
  • 整个表达式可以分为五个部分:- execution(): 表达式主体- 第一个号:方法返回类型, 号表示所有的类型- 包名:表示需要拦截的包名- 第二个号:表示类名,号表示所有的类- (…):最后这个星号表示方法名,号表示所有的方法,后面( )里面表示方法的参数,两个句点表示任何参数
<!--切入点--><!--execution(修饰符返回值 类路径.*(..))--><aop:pointcutid="point"expression="execution(* com.wei.service.UserServiceImpl.*(..))"/>

方式三:使用注解实现AOP

  • 创建AnnotationPointCut类
//方式三:使用注解实现AOP//  @Aspect 标注这个类是一个切面@AspectpublicclassAnnotationPointCut{//后置增强@Before("execution(* com.wei.service.UserServiceImpl.*(..))")publicvoidbefore(){System.out.println("======方法执行前======");}//前置增强@After("execution(* com.wei.service.UserServiceImpl.*(..))")publicvoidafter(){System.out.println("======方法执行后======");}//在环绕增强中,可以给一个参数,代表要获取处理切入的点@Around("execution(* com.wei.service.UserServiceImpl.*(..))")publicvoidaround(ProceedingJoinPoint jp)throwsThrowable{System.out.println("======环绕前======");//执行方法Object proceed = jp.proceed();System.out.println("======环绕后======");}}
  • 将AnnotationPointCut类注册到Spring中,即applicationContext.xml中
<!--方式三--><beanid="AnnotationPointCut"class="com.wei.diy.AnnotationPointCut"/><!--开启注解支持--><!--
JDK(默认 proxy-target-class="false")  cglib(proxy-target-class="true")
--><aop:aspectj-autoproxyproxy-target-class="true"/>
  • MyTest测试类
publicclassMyTest{publicstaticvoidmain(String[] args){ApplicationContext context =newClassPathXmlApplicationContext("applicationContext.xml");//动态代理的是接口UserService userService =(UserService) context.getBean("userService");
        userService.delete();}}/*
执行结果:
======环绕前======
======方法执行前======
删除了一个用户
======环绕后======
======方法执行后======
*/

🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——

点赞

👍

收藏

⭐️

评论

📝

冲冲冲

🤞



本文转载自: https://blog.csdn.net/weixin_62765017/article/details/127612410
版权归原作者 wei_shuo 所有, 如有侵权,请联系我们删除。

“Spring AOP实现 | 代理模式分析”的评论:

还没有评论