首页 > 编程知识 正文

spring动态代理原理,静态代理和动态代理的区别

时间:2023-05-05 09:20:47 阅读:20653 作者:4994

学习Spring的时候,我知道Spring主要有IoC和AOP两种思想。 对于IoC,依赖注入自不必说,对于以Spring为中心的AOP,不仅需要知道AOP如何满足功能,还需要学习其基础是什么原理。 AOP的原理是jaop

java的动态代理机制有两个重要的类或接口。 一个是invocation handler (接口),另一个是proxy (代理)类。 实现动态代理时需要这个类和接口。 首先,让我们看看java的API帮助文档是如何描述这两个类的。

InvocationHandler:

每个动态代理类都必须实现一个名为InvocationHandler的接口,每个代理类的实例都与handler相关联。 从代理对象调用方法时,接口为InvocationHandler的invoke方法调用该方法。 让我们看看一个名为InvocationHandler的界面的唯一方法invoke方法:

对象邀请(对象代理,方法方法,对象[ ] args ) throws Throwable

我们看到这个方法一共接受了三个参数,这三个参数分别代表什么呢?

对象代理(object proxy,Method Method,Object[] args ) throwableproxy:由我们代理的真实对象method:调用

让我们看看一个叫Proxy的类

类“代理”的作用是用于动态创建代理对象的类,提供了许多方法,但最常用的方法是newProxyInstance。

publicstaticobjectnewproxyinstance (类加载器加载器,类? [] interfaces,invocationhandlerh ]方法throwsillegalargumentexception的作用是获得接收三个参数的动态代理对象。 让我们来看看这三个参数所表示的含义。

publicstaticobjectnewproxyinstance (类加载器加载器,类? [ ]接口,invocationhandlerh (throwsillegalargumentexceptionloader 3360 class loader对象,哪个clarader用于加载生成的代理对象它指示代理为需要代理的对象提供了一组什么接口,如果提供了一组接口,则该代理对象声称实现了该接口。 (多态性)。 现在,您可以调用该组接口的方法。 h:上的InvocationHandler对象指示动态代理对象调用方法时与哪个InvocationHandler对象相关联

代理类通过程序运行时创建代理类的方式称为动态代理。 与静态代理自己定义代理类并在运行程序之前编译代理类不同,动态代理的代理类是在系统运行时动态生成的,而不是由代码定义的。

动态代理的有用性:

既然动态代理是AOP实现,那么动态代理的角色必须与AOP相同。 也就是说,它主要用于方法的扩展。 这样,可以在不修改源代码的情况下扩展方法,并在方法执行前后做任何想做的事情。 因为InvocationHandler的invoke方法可以直接访问调用该方法的Method方法

动态代理的具体实现

动态代理是实现InvocationHandler的类,也称为事务处理程序。

具体实施步骤如下。

1 .创建被代理的类和接口

必须创建具有实现InvocationHandler的接口的类,并实现invoke (方法

Proxy静态方法在newProxyInstance中创建代理类对象

4 .从代理类的对象调用方法

AOP

辅助编程(AOP )是指面向切面编程,

通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Aop Spring 中的作用 提供声明式事务;允许用户自定义切面 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要 关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 .... 切面( ASPECT ):横切关注点 被模块化 的特殊对象。即,它是一个类。 通知( Advice ):切面必须要完成的工作。即,它是类中的一个方法。 目标( Target ):被通知对象。 代理( Proxy ):向目标对象应用通知之后创建的对象。 切入点( PointCut ):切面通知 执行的 “ 地点 ” 的定义。 连接点( JointPoint ):与切入点匹配的执行点。 SpringAOP 中,通过 Advice 定义横切逻辑, Spring 中支持 5 种类型的 Advice:

 

   使用 Spring 实现 Aop 【重点】使用 AOP 织入,需要导入一个依赖包! <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency>

通过 Spring API 实现 public class Log implements MethodBeforeAdvice { // 要执行目标对象的方法 @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName()+"的"+method.getName()); }}

<bean id="Log" class="log.Log"/> <bean id="userService" class="Bean.UserServiceImpl"/> <!--aop配置--> <aop:config> <!--切入点--><!--切入点 expression:表达式匹配要执行的方法--> <!--两个点便是任意参数--> <aop:pointcut id="pointcut" expression="execution(* Bean.UserServiceImpl.*(..))"/> <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--> <aop:advisor advice-ref="Log" pointcut-ref="pointcut"/> </aop:config>

/*代理的是接口,所以转换接口类型*/ UserService userService = (UserService) applicationContext.getBean("userService"); // 执行方法 userService.add();

第二种方式 自定义类来实现 Aop 目标业务类不变依旧是 userServiceImp 第一步 : 写我们自己的一个切入类  

public class DiyPointcut {public void before(){System.out.println("---------方法执行前---------");}public void after(){System.out.println("---------方法执行后---------");}}

去 spring 中配置

<!--第二种方式自定义实现--><!--注册bean--><bean id="diy" class="com.kuang.config.DiyPointcut"/><!--aop的配置--><aop:config><!--第二种方式:使用AOP的标签实现--><aop:aspect ref="diy"><aop:pointcut id="diyPonitcut" expression="execution(*com.kuang.service.UserServiceImpl.*(..))"/><aop:before pointcut-ref="diyPonitcut" method="before"/><aop:after pointcut-ref="diyPonitcut" method="after"/></aop:aspect></aop:config>

第三种方式 使用注解实现 第一步:编写一个注解实现的增强类 package com.kuang.config;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;@Aspectpublic class AnnotationPointcut {@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")public void before(){System.out.println("---------方法执行前---------");}@After("execution(* com.kuang.service.UserServiceImpl.*(..))")public void after(){System.out.println("---------方法执行后---------");}@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("环绕前");System.out.println("签名:"+jp.getSignature());//执行目标方法proceedObject proceed = jp.proceed();System.out.println("环绕后");System.out.println(proceed);}}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。