首页 > 其他分享 >动态代理和静态代理

动态代理和静态代理

时间:2024-01-09 22:11:13浏览次数:35  
标签:target 静态 Object 代理 Person 对象 动态 public

先说一下代理模式的好处:

  1. 隐藏真实对象的复杂性:Java 代理模式可以隐藏真实对象的复杂性,客户端只需要与代理对象交互即可,不需要了解真实对象的复杂实现细节,从而简化了客户端的代码实现和维护。
  2. 增强真实对象的功能和可靠性:Java 代理对象可以在访问真实对象之前或之后执行一些额外的操作,例如日志记录、性能监控、安全控制等,从而增强了真实对象的功能和可靠性。
  3. 缓存机制:Java 代理模式可以实现缓存等机制,从而减少对真实对象的访问次数,提高系统的响应速度和吞吐量。
  4. 避免客户端直接访问真实对象:Java 代理模式可以避免客户端直接访问真实对象,从而降低了系统的耦合度和复杂度,使得系统更易于维护和扩展。

总的来归纳就是可以不要管原来的多么复杂,在某时刻某场合我只运行我想运行的就可以,并且像之前基于springboost的aop就是很好的例子,我想记录运行的时间不需要在每个方法都添加记录时间的方法,只要交给切面类就可以,这个就有点像代理模式下的代理类,其他的好处就是像减少访问次数等利于开发的好处。

静态代理:

静态代理需要先定义接口或者父类,被代理对象与代理对象一起实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。通俗说就是在原来的类中我们可以定义一个代理类,通过这个代理类我就可以指定的运行原来某些的方法并添加方法。

public interface Person {

	//租房
	public void rentHouse();
}
===================================================
public class Renter implements Person{

	@Override
	public void rentHouse() {
		System.out.println("租客租房成功!");
		
	}

}
=================================================== 
public class RenterProxy implements Person{
	private Person renter;
	public RenterProxy(Person renter){
		this.renter = renter;
	}
	@Override
	public void rentHouse() {
		System.out.println("中介找房东租房,转租给租客!");
		renter.rentHouse();
		System.out.println("中介给租客钥匙,租客入住!");
		
	}

}
=================================================== public class StaticProxyTest { public static void main(String[] args) { Person renter = new Renter(); RenterProxy proxy = new RenterProxy(renter); proxy.rentHouse(); } }
=================================================== //中介找房东租房,转租给租客! //租客租房成功! //中介给租客钥匙,租客入住!

此时就可以不通过原来的类官方好像叫什么委托类执行代码,减少了访问次数这个貌似在编写的时候体会不到好处,但是一但在开发中 访客量大的时候就可以减少服务器的压力了,当然这个也有不足,像要额外增加方法那么又要一个个改,解决方法就不赘述了,在开发中可以使用切面类等方法

动态代理:

代理类在程序运行时创建的代理方式被成为动态代理。在静态代理中,代理类(RenterProxy)是自己已经定义好了的,在程序运行之前就已经编译完成。而动态代理是在运行时根据我们在Java代码中的“指示”动态生成的。动态代理相较于静态代理的优势在于可以很方便的对代理类的所有方法进行统一管理,如果我们想在每个代理方法前都加一个方法,如果代理方法很多,我们需要在每个代理方法都要写一遍,很麻烦。而动态代理则不需要。

注意:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。(此步骤便是核心所在)

  1. InvocationHandler:该接口包含一个invoke方法,当代理对象调用方法时,会自动调用该方法,invoke方法中包含了代理对象、调用的方法及参数等信息,通过该方法可以实现对真实对象的代理操作。
  2. Proxy:该类是Java提供的用于创建动态代理对象的类,它提供了一个静态方法newProxyInstance,可以在运行时动态生成代理类,并返回一个代理对象,该代理对象可以强制转换为任意接口或类,从而实现对该接口或类的代理操作。

 

public interface Person {

	//租房
	public void rentHouse();
}
===========================
public class Renter implements Person{

	@Override
	public void rentHouse() {
		System.out.println("租客租房成功!");
		
	}

}
===============================
/*
创建RenterInvocationHandler类,这个类实现了InvocationHandler接口,并持有一个被代理类的对象,InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。然后通过反射在invoke方法中执行代理类的方法。在代理过程中,在执行代理类的方法前或者后可以执行自己的操作,这就是spring aop的主要原理
*/
public class RenterInvocationHandler<T> implements InvocationHandler{
	//被代理类的对象
	private T target;
	
	public RenterInvocationHandler(T target){
		this.target = target;
	}

	/**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//代理过程中插入其他操作
		System.out.println("租客和中介交流");
		Object result = method.invoke(target, args);
		return result;
	}

}
==============================
public class ProxyTest {

	public static void main(String[] args) {

		//创建被代理的实例对象
		Person renter = new Renter();
		//创建InvocationHandler对象
		InvocationHandler renterHandler = new RenterInvocationHandler<Person>(renter);
		
		
		//创建代理对象,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
		Person renterProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, renterHandler);
		renterProxy.rentHouse();
		
		//也可以使用下面的方式创建代理类对象,Proxy.newProxyInstance其实就是对下面代码的封装
		/*try {
			//使用Proxy类的getProxyClass静态方法生成一个动态代理类renterProxy 
			Class<?> renterProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
			//获取代理类renterProxy的构造器,参数为InvocationHandler
			Constructor<?> constructor = renterProxyClass.getConstructor(InvocationHandler.class);
			//使用构造器创建一个代理类实例对象
			Person renterProxy = (Person)constructor.newInstance(renterHandler);
			renterProxy.rentHouse();
			//
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
	}

}

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable这个相当于是固定写法,后面的invoke就是使用原来类的方法

动态代理有一个最致命的问题是它只能代理实现了某个接口的实现类,并且代理类也只能代理接口中实现的方法,要是实现类中有自己私有的方法,而接口中没有的话,该方法不能进行代理调用。

 

CGLIB 动态代理机制:

Cglib代理也叫作子类代理,他是通过在内存中构建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,然后加入自己需要的操作。因为使用的是继承的方式,所以不能代理final 类

 

累了效率太低了放两段代码自行体会吧

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before method " + method.getName());
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("after method " + method.getName());
        return result;
    }
}

public class UserServiceImpl {
    public void addUser(String userName) {
        System.out.println("add user: " + userName);
    }
}

public class Main {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        CglibProxy proxy = new CglibProxy(userService);
        UserServiceImpl userServiceProxy = (UserServiceImpl) proxy.getProxy();
        userServiceProxy.addUser("test");
    }
}

  

public class UserService {
	
	public void getName(){
		System.out.println("张三!");
	}

}
============
public class ProxyFactory<T> implements MethodInterceptor {

	private T target;

	public ProxyFactory(T target) {
		this.target = target;
	}

	// 创建代理对象

	public Object getProxyInstance() {

		// 1.cglib工具类
		Enhancer en = new Enhancer();
		// 2.设置父类
		en.setSuperclass(this.target.getClass());
		// 3.设置回调函数
		en.setCallback(this);

		return en.create();
	}

   //拦截方法
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable {
		System.out.println("开始事务...");

		// 执行目标对象的方法
		Object result = method.invoke(target, args);

		System.out.println("提交事务...");
		return result;
	}

}

  

标签:target,静态,Object,代理,Person,对象,动态,public
From: https://www.cnblogs.com/sixsix666/p/17955459

相关文章

  • js 静态分配与对象池
    为了提升JavaScript性能,最后要考虑的一点往往就是压榨浏览器了。此时,一个关键问题就是如13何减少浏览器执行垃圾回收的次数。开发者无法直接控制什么时候开始收集垃圾,但可以间接控制触发垃圾回收的条件。理论上,如果能够合理使用分配的内存,同时避免多余的垃圾回收,那就可以保住因......
  • 17. 从零用Rust编写正反向代理, Rust中一些功能的实现
    wmproxywmproxy是由Rust编写,已实现http/https代理,socks5代理,反向代理,静态文件服务器,内网穿透,配置热更新等,后续将实现websocket代理等,同时会将实现过程分享出来,感兴趣的可以一起造个轮子法项目地址gite:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/wmpr......
  • Gateway动态路由配置——Nacos
    Gateway一般配置路由的方式有三种,代码、文件、注册中心,但个人感觉使用注册中心的方式去动态更新路由的方式更能契合项目,但是配置会比较麻烦,不如文件和代码去配置简单Nacos加入配置:gateway-router我这里使用的是Json格式id:唯一idpredictates:断言,我使用的是Path断言uri:真实请求的上......
  • 优化CentOS 7.6的HTTP隧道代理网络性能
    在CentOS7.6上,通过HTTP隧道代理优化网络性能是一项复杂且细致的任务。首先,我们要了解HTTP隧道代理的工作原理:通过建立一个安全的隧道,HTTP隧道代理允许用户绕过某些网络限制,提高数据传输的速度和安全性。然而,由于数据需要在中间节点进行转发,因此可能会引入额外的延迟。优化网络性能......
  • 在Linux中设置HTTP代理服务器
    在Linux中设置HTTP代理服务器涉及到几个关键步骤。下面是一个简单的指南,帮助你设置一个基本的HTTP代理服务器:1. 选择代理软件:有许多软件可以用来设置HTTP代理服务器,其中一些流行的选择包括Squid、Privoxy和Polipo。在本指南中,我们将使用Squid作为示例。2. 3. 安装Squid:首先,你需......
  • 【Spring技术专题】「实战开发系列」保姆级教你SpringBoot整合Mybatis框架实现多数据
    Mybatis是什么Mybatis是一个基于JDBC实现的,支持普通SQL查询、存储过程和高级映射的优秀持久层框架,去掉了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。Mybatis主要思想是将程序中大量的SQL语句剥离出来,配置在配置文件中,以实现SQL的灵活配置。在所有ORM框......
  • 程序员必知!代理模式的实战应用与案例分析
    代理模式是在不改变原对象基础上,通过代理对象控制访问并添加额外操作,以销售代表和助理为例,助理作为代理对象,处理邮件、数据等琐碎工作,使销售代表能专注于与客户面对面交流推销,代理模式让原对象功能得以扩展,同时保持其对外接口的透明性。定义代理模式提供了一种在不改变原有对......
  • 16. 从零用Rust编写正反向代理, 反向代理upstream源码实现
    wmproxywmproxy是由Rust编写,已实现http/https代理,socks5代理,反向代理,静态文件服务器,内网穿透,配置热更新等,后续将实现websocket代理等,同时会将实现过程分享出来,感兴趣的可以一起造个轮子法项目wmproxygite:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/......
  • 使用Ruby编写的代理爬虫程序:抓取dy视频播放量接口数据并解析(附详细中文解释)
    随着互联网的快速发展,网络数据的获取变得愈发重要。在某些情况下,我们可能需要通过代理来访问特定的网站或API,以确保数据的准确性和可靠性。本文将介绍如何使用Ruby编写一个代理爬虫程序,以抓取dy视频播放量接口的数据并进行解析。准备工作首先,我们需要引入两个关键的Ruby库:open-uri......
  • MyBatis—Spring 动态数据源事务的处理
    在一般的Spring应用中,如果底层数据库访问采用的是MyBatis,那么在大多数情况下,只使用一个单独的数据源,Spring的事务管理在大多数情况下都是有效的。然而,在一些复杂的业务场景下,如需要在某一时刻访问不同的数据库,由于Spring对于事务管理实现的方式,可能不能达到预期的效果。本文......