Java高级编程:代理机制的理解与应用

代理机制的理解与应用

1.概述:

在Java的框架Spring中,有两个很重要的的概念:IOC和AOP,其中IOC(Inversion of Control ,控制反转)是其实现面向切面编程的重要执行手段。其中有一个比较重要的实现方式就是代理机制。代理机制,就是将一个已经封装好的类(很有可能已经成为二进制字节码,无法更改源代码),用一个新的类(代理类)来代替他执行。这样做的最大优点就是可以在原始类的某个方法执行时,在执行前后(所谓的切面)增加一些业务。代理机制主要分为静态代理和动态代理,下面我们就来看一下这两个代理。

2.静态代理(代理模式):

静态代理严格意义上是一种设计模式,为了让大家更好的理解代理模式的原理,先介绍一下静态代理(也叫代理模式)。

第一步:建立接口

package com.my.about_staticProxy;

public interface Interface {
	public void doSomthing();
}

第二步:建立原始类

package com.my.about_staticProxy;

public class UserClass implements Interface{

	@Override
	public void doSomthing() {
		System.out.println("做了一些事情");
		
	}

}

第三步:建立代理类

package com.my.about_staticProxy;

public class UserProxy implements Interface{
	private Interface user = new UserClass();
	
	@Override
	public void doSomthing() {
		System.out.println("执行前做的事");
		user.doSomthing();
		System.out.println("执行后做的事");	
	}

}

测试类:

package com.my.about_staticProxy;

public class Test {
	public static void main(String arg[]) {
		UserProxy userproxy = new UserProxy();
		userproxy.doSomthing();
	}
}

测试结果:
Java高级编程:代理机制的理解与应用
静态代理主要是依赖接口类来创建代理对象,因为其已经拥有原始类的对象,所以被称为静态代理(代理模式)。静态代理的源码比较简单,在这里就不再赘述,不过这里的代码对于动态代理的理解具有一定的意义,希望初学者能够充分的理解。

3.动态代理:

Spring中实现的IOC容器,主要就是基于动态代理实现,所以动态代理是Java高级编程中非常重要的的内容,其主要的实现方式有两种最常用的方式:一是通过反射机制,创建基于原始类接口的代理对象;二是通过CGLib,通过字节码直接生成原始类的子类。两种实现各有优劣,下面我们结合源代码具体分析。

(1)JDKProxy:

代理的第一种实现方式是常规的通过反射机制形成代理的方式,以下为源代码:
原始类同上;
JDKProxy:

package com.my.about_staticProxy.JDKProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.my.about_staticProxy.Interface;

public class JDKProxy{
	public JDKProxy() {
		// TODO Auto-generated constructor stub
	}
	
	@SuppressWarnings("unchecked")
	//使用泛型创建获得代理方法,可以在使用时无需强转
	public <T> T getJDKProxy(Object object) {
		Class<?> klass = object.getClass();
		
		return (T)Proxy.newProxyInstance(
				klass.getClassLoader(), 
				klass.getInterfaces(), 
				//通过InvocationHandler() 方法来具体实现代理
				new InvocationHandler() {
			
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						Object result = null;
						
						System.out.println("在调用方法" + method.getName() + "前执行");
						result = method.invoke(object, args);//反射执行被代理的方法
						System.out.println("在调用方法" + method.getName() + "前执行");
						
						return result;
					}
		});
		
	}
}

测试类:

package com.my.about_staticProxy.JDKProxy;

import com.my.about_staticProxy.Interface;
import com.my.about_staticProxy.UserClass;

public class Test {

	public static void main(String[] args) {
		Interface userProxy = new JDKProxy().getJDKProxy(new UserClass());
		
		userProxy.doSomthing(); 
	}

}

测试结果:
Java高级编程:代理机制的理解与应用
java.lang.reflect.Proxy包中的代理是基于接口实现的,通过反射机制,动态的生成代理类,实现代理方法。其最大的缺点在于,原始类必须拥有接口,并且原始类中非接口的方法无法被代理。

(2)CGLProxy:

CGLIB是动态字节码生成库,通过系统运行期间动态地为目标对象生成相应的扩展子类。在使用时必须导入相应的cglib工具包。代码实现如下:
原始类同上
CGLProxy:

package com.my.about_staticProxy.JDKProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import com.my.about_staticProxy.Interface;

public class JDKProxy{
	public JDKProxy() {
		// TODO Auto-generated constructor stub
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getCGLProxy(Object object) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(object.getClass());
		MethodInterceptor methodInterceptor = new MethodInterceptor() {
			
			@Override
			public Object intercept(Object obj, Method method, Object[] args,
					MethodProxy methodProxy) throws Throwable {
				Object result = null;
				
				System.out.println("在调用方法" + method.getName() + "前执行");
				result = method.invoke(object, args);
				System.out.println("在调用方法" + method.getName() + "前执行");
				
				return result;
			}
		};
		enhancer.setCallback(methodInterceptor);
 		
		return (T) enhancer.create();
		
	}
}

测试类:

package com.my.about_staticProxy.JDKProxy;

import com.my.about_staticProxy.Interface;
import com.my.about_staticProxy.UserClass;

public class Test {

	public static void main(String[] args) {
		UserClass userProxy = new JDKProxy().getCGLProxy(new UserClass());
		
		userProxy.doSomthing(); 
	}

}

测试结果:
Java高级编程:代理机制的理解与应用

CGLIB主要是由Enhancer最终为我们生成所需要的代理。其主要的缺点是不能对final方法进行覆写。

总结:

代理机制是Spring的基础之一,本篇博客只介绍其中的两种操作,各有有优劣,读者可以根据自己的需要选用适合的代理。这里只介绍代理机制的最基础内容,如果想看后续的操作可以继续关注博主的博客的后续博客。(令:感谢教主的教导)。