首页 > 编程知识 正文

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

时间:2023-05-06 18:33:39 阅读:138227 作者:3997

什么是AOP? 通过上一章的学习,我们知道Spring致力于简化我们的Java开发,并使用了非常重要的技术——依赖注入和辅助有序编程(AOP )。

DI主要解决了类与类之间存在依赖关系时,如何通过注入方式(属性注入、构造函数注入)形成松耦合

今天学习的AOP是考虑如何剥离分散在APP应用中的多个相同的功能,将这些剥离的逻辑和业务逻辑分离的问题。

先看看生活中的案例:

家家户户都有监控用电量的电表,电力公司可以知道应该收取多少费用。 每个电器都可以自行制作电气统计硬件,这是极不合理的,成本上也不划算。 因为关注每个电器自身功能是否完备的问题,考虑吸尘器的清扫效果、微波炉的加热效果等。 电力公司在合适的地方,例如使用电线入户的地方,只需统一安装一个电表,就可以很好地解决监控所有用电设备电量的问题。

软件系统的一些功能就像我们家的电表一样。 这些功能需要在APP应用程序的很多地方使用,但不想在所有的点都被显式调用。

在软件开发中,驻留在APP上的许多功能被称为http://www.Sina.com/(cross-cutting concern )。 这些横向关注点通常在概念上与APP应用程序的业务逻辑分离。 但是,它们往往直接嵌入到APP应用程序的业务逻辑中。 将这些横向关注点和业务逻辑分开是AOP需要解决的问题。

代理模式代理模式概念AOP在实现中采用了设计模式中的动态代理模式,所以在深入学习SpringAOP之前,我们一起了解并学习一下这个强大的设计模式吧。

定义代理模式:为其他对象提供代理并控制对该对象的访问。 换句话说,这是一种使用代理对象运行目标对象并在代理对象中增强目标对象方法的设计模式。

生活中最常见的代理模式是“中介”。 如果我现在说想买二手车的话,可以自己去找车位,做质检等一系列的车辆通过流程,但这确实太费时间和精力了。 我只是想买车,为什么我还要加这么多? 所以我通过中介公司来买车。 他们来找我车的货源,帮我处理了车的过户流程。 我只是选择自己喜欢的车,付钱就行了。

代理模式的功能主要起到强化方法和权限拦截的作用。

代理模式的优点从上面的图表中可以看出,在编程中使用代理模式有几个优点。

代理隔离:如果调用者Caller无法或不希望与目标对象Target直接交互,代理对象Proxy可以起到两者之间的中介作用。 开闭原则:可以通过向代理对象添加新功能来扩展目标对象的功能。 这样,只需修改代理类,而无需修改目标类,就可以遵循代码设计的OCP原则。 (Open Closed Principle,对扩展开放,对修改封闭)。 代理模式的类型根据代理对象的创建分为以下两种代理模式:

静态代理:程序员或特定工具通过生成源代码来生成代理对象。 在程序运行之前,代理类的字节码文件. class中已经存在动态代理。 在程序运行过程中,采用反射机制、字节码生成技术生成代理类和实例。 静态代理模式Proxy—要使代理实现静态代理,请首先使用接口封装代理行为。

接口:

publicinterfaceiuserdao { void save (; }通过在目标和代理上都实现此接口,调用方无论是与代理还是与目标进行交互,执行的代码都是一致的,并且可以执行相同的行为。

publicclassuserdaoimplimplementsiuserdao { @ overridepublicvoidsave () system.out.println (保存用户数据! ' ); }创建与目标对应的代理类,并在其中添加新的服务功能:

package com.tuling.dao; publicclassuserdaoproxyimplementsiuserdao { privateiuserdaouserdao; publicuserdaoproxy (iuserdaouserdao ) { this.userDao=userDao; } @Override public void save (() { System.out.println ) );打开事务. ); userDao.save (; //目标对象方法System.out.println ('提交事务.'); }综上所述,我们最终让客户执行了购买行为,除此之外,为了享受更完善的服务,我们还扩展了其他服务,如寻找货源、质检、售后服务等。 在复杂的APP应用程序中,当然除了打印几行字外,还可以封装各个方法来完成这些操作,或者调用其他类来执行这些辅助逻辑。

测试代码:

package com.tuling

.dao;public class MainTest { public static void main(String[] args) { //目标对象 UserDaoImpl userDao = new UserDaoImpl(); //代理对象 UserDaoProxy proxy = new UserDaoProxy(userDao); //执行代理对象的方法 proxy.save(); } /* * 静态代理总结: * 1、可以做到在不修改目标对象的功能前提下,增强目标对象。 * 2、但是由于要和目标对象实现相同的接口,如果目标方法过多,或者 * 目标对象一旦新增方法,代理对象都要一并维护。 */} 动态代理模式

静态代理模式最大的缺陷就是,我们需要为每一个被代理的目标类都编写一个代理类。而动态代理可以很好的解决这个问题。JDK的Proxy和开源框架CGLIB可以分别在不同的情况帮助我们生成代理。

JDK动态代理

当目标的被代理方法抽取了接口时,可以使用JDK Proxy。

接口:

package com.tuling.proxy;/*** 接口* @author fred**/public interface IUserDao { void save();}

目标类:

package com.tuling.proxy;public class UserDaoImpl implements IUserDao { @Override public void save() { System.out.println("用户数据保存!"); }}

测试类:

package com.tuling.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class MainTest { public static void main(String[] args) { //目标对象 UserDaoImpl userDao = new UserDaoImpl(); //代理对象 IUserDao proxy = (IUserDao) Proxy.newProxyInstance( userDao.getClass().getClassLoader(), //目标对 象的类加载器 userDao.getClass().getInterfaces(), //目标对 象的接口数组 new InvocationHandler() {//事件处理,执行目标对 象的方法时,会触invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务..."); //执行目标对象方法 Object obj = method.invoke(userDao, args); System.out.println("提交事务..."); return obj; } }); //调用代理对象方法 proxy.save(); /* * JDK动态代理总结: * 1、目标对象必须要有接口,否则不能实现动态代理。 * 2、代理对象必须强转为接口类型。 */ }}

invoke方法会在代理对象的被代理方法调用的时候触发。

CGLIB

当目标类没有实现接口时,我们可以通过开源的CGLIB来实现。

使用maven引入cglib库:

<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version></dependency>

也可以引入spring-core库,该库中包含了CGLIB。

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.2.RELEASE</version></dependency>

目标类:

package com.tuling.cglib;/*** 目标对象,没有任何接口* @author fred**/public class UserDaoImpl{ public void save() { System.out.println("用户数据保存!"); }}

代理工厂类:

package com.tuling.cglib;import java.lang.invoke.MethodHandleInfo;import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class ProxyFactory implements MethodInterceptor{ //目标对象 private Object target; public ProxyFactory(Object target) { super(); this.target = target; } //给目标对象创建一个代理对象 public Object getProxyInstance(){ //1.增强器 Enhancer en = new Enhancer(); //2.设置目标对象的类加载器 en.setClassLoader(target.getClass().getClassLoader()); //3.设置这个动态代理类的父类 en.setSuperclass(target.getClass()); //4.设置要传入的拦截器 en.setCallback(this); //5.创建子类(代理对象) return en.create(); } @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { System.out.println("开启事务..."); //执行目标对象的方法 Object obj = method.invoke(target, args); System.out.println("提交事务..."); return obj; }}

测试类:

package com.tuling.cglib;public class MainTest { public static void main(String[] args) { //目标对象 UserDaoImpl userDao = new UserDaoImpl(); //代理对象 UserDaoImpl proxy = (UserDaoImpl) new ProxyFactory(userDao).getProxyInstance(); //执行代理对象方法 proxy.save(); }} 总结

静态代理需要自己手动编写代理类和目标方法。

动态代理就不需要自己手动实现代理类和目标方法,但动态代理的目标类要必须实现接口!

Cglib 代理的目标类就不需要实现接口!但目标类不能被final修饰!

Spring AOP 编程的实现原理就是 动态代理和Cglib 代理,当目标类实现接口时使用动态代理,没有则Cglib代理。

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