JAVA动态代理的作用

先定义一个接口类,该接口是我们要代理的接口


public interface Subject
{
	public void rent();
	public void hello(String str);
}

接下来是一个实现类


public class RealSubject implements Subject
{

	@Override
	public void rent()
	{
		System.out.println("i want to rent my house");
	}

	@Override
	public void hello(String str)
	{
		System.out.println("hello:"+str);
	}


}

接下来是动态代理类, 该类必须实现InvocationHandler接口


public class DynamicProxy implements InvocationHandler
{
	private Object subject;

	public DynamicProxy(Object subject)
	{
		super();
		this.subject = subject;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable
	{
		System.out.println("before method:" + method.getName());
		method.invoke(subject, args);
		System.out.println(method);
		System.out.println("after method:" + method.getName());
		return subject;
	}

}


接下来是测试类,用来测试动态代理的机制,以及作用


/*
 * 动态代理的作用:
 * 在实现要代理的对象的核心功能的基础上
 * 添加额外的一些功能
 */
public class Client
{
	
	@Test
	public void mainTest()
	{
		// 利用代理机制创建了一个跟realSubject实现了相同接口的类
		Subject realSubject = new RealSubject();
		InvocationHandler handler = new DynamicProxy(realSubject);
		// 制定要创建的代理实例使用的ClassLoader、要实现的哪些接口、代理该实例的代理类(invocationHandler)
		Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass()
				.getClassLoader(), new Class[]
		{ Subject.class }, handler);
		System.out.println(subject.getClass().getName() + "与" + realSubject
				+ "作比较");
		realSubject = null;
		subject.rent();
		subject.hello("world");
	}

	@Test
	public void myProxy()
	{
		Subject realSubject = new RealSubject();
		Class[] intefaces = realSubject.getClass().getInterfaces();
		for (Class t : intefaces)
		{
			System.out.println("接口:" + t + "===========");
			Method[] methods = t.getMethods();
			for (Method m : methods)
			{
				System.out.println("执行方法:" + m.getName() + "=======");
				System.out.println("before====>" + m.getName());
				try
				{
					Class[] params = m.getParameterTypes();
					if (params != null && params.length > 0)
					{
						m.invoke(realSubject, "World");
					} else
					{
						m.invoke(realSubject);
					}
				} catch (IllegalAccessException | IllegalArgumentException
						| InvocationTargetException e)
				{
					e.printStackTrace();
				}
				System.out.println("after====>" + m.getName());
			}
		}
	}

	@Test
	public void myProxy2()
	{
		Subject realSubject = new RealSubject();
		Method rent;
		try
		{
			rent = realSubject.getClass().getMethod("rent");
			System.out.println("执行方法:" + rent.getName() + "=======");
			System.out.println("before====>" + rent.getName());
			rent.invoke(realSubject);
			System.out.println("after====>" + rent.getName());
		} catch (NoSuchMethodException | SecurityException e)
		{
			e.printStackTrace();
		} catch (IllegalAccessException e)
		{
			e.printStackTrace();
		} catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		} catch (InvocationTargetException e)
		{
			e.printStackTrace();
		}
	}
}


mainTest方法创建了一个realSubject的动态代理实例subject,当调用subject的方法时,会自动调用handler对象里面的invoke方法,在invoke方法里面,会调用我们要代理的对象(realSubject)的方法,我们可以在调用realSubject对象的方法前后加上一些其他的逻辑,这也是Spring AOP机制的实现原理

在看动态代理机制时,我有一个疑问,就是为什么要用到动态代理,需求何在?

网上搜了很多资料,很多答案都文绉绉的,看起来不是很好懂,就我自己的理解,使用动态代理,其实就是为了方便在实现一个对象的某个方法前后,添加一些其他的逻辑,如上的myProxy2()方法,使用反射也可以达到这个目的,但是这样的实现想比动态代理而言,逻辑性比较差,而且当动态代理使用的地方有多处时,前后添加的逻辑没能聚拢到一个地方,每次都要反射拿到方法,然后在执行方法的前后再添加逻辑,这样用不好维护,如果用动态代理,虽然创建代理对象时比较麻烦,但是当代理对象创建好以后,可以直接使用例如 subject.rent(); 这样的方式,直接调用方法,前后添加的逻辑在hanlder的invoke方法里面已经实现好了

 要注意的一点是,subject对象实际上不是一个Subject类或者RealSubject类,而是一个com.sun.proxy.$Proxy这样的类

在handler对象的invoke方法里面,参数Object proxy 实际上没用用到,如果试着去打印出这个参数,会报错,具体原因我也不清楚,使用该方法,实际上用的是创建该handler时传进去的realSubject对象,而使用代理对象subject的方法时,会去调用handler里面的invoker方法,所以,当我们调用代理对象subject的方法时,其实是调用了真实对象

realSubject的方法


以上都是个人见解,如果有不对的地方,恳请大家帮忙指出,感激不尽