动态代理和静态代理

发布时间 2024-01-09 22:10:08作者: sixsix666

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

  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;
	}

}