`
tcspecial
  • 浏览: 897719 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java 动态代理

    博客分类:
  • java
阅读更多

 

Spring框架两大核心原理:AOP和IOC,IOC Inversion of control 用来解决依赖关系,通过工厂模式实现。

AOP Aspect of programming 通过动态代理实现。

 

1. 定义接口

/**
 * 用户服务接口
 * @author lingsun
 *
 */
public interface UserService {
	public String getName();
	public Integer getAge();
}


/**
 * 用户服务实现类
 * @author sunling3
 *
 */
public class UserServiceImpl implements UserService {
	@Override
	public String getName() {
		System.out.println( "---- GetName" );
		return "Sun";
	}

	@Override
	public Integer getAge() {
		System.out.println( "---- GetAge" );
		return 18;
	}
}

 

2. 方法一:反射实现

/**
 * 反射实现动态代理
 * @author lingsun
 *
 */
public class MyInvocationHandler implements InvocationHandler {
	private Object target;
	
	MyInvocationHandler(){
		super();
	}
	
	MyInvocationHandler( Object target ){
		super();
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 只拦截getName
		if( method.getName() == "getName" ){
			
			System.out.println( "------- before------->" );
			Object result = method.invoke( target, args);
			System.out.println( "<------- after--------" );
			
			return result;
		}else{
			Object result = method.invoke( target, args );
			return result;
		}
	} 
	
	/**
	 * main
	 * @param args
	 */
	public static void main(String[] args) {
		// 接口
		UserService service = new UserServiceImpl();
		InvocationHandler handler = new MyInvocationHandler( service );
		
		// 注入代理
		UserService userServie = (UserService)Proxy.newProxyInstance(service.getClass().getClassLoader(), 
				service.getClass().getInterfaces(), 
				handler);
		
		// 代理对象实现了UserService接口(2),能动态生成UserService对象
		System.out.println("Proxy: " + userServie.getClass().getName());
		
		// 委托代理调用 --- 动态代理
		userServie.getName();
		userServie.getAge();
	}
}

 

执行结果:

Proxy: com.sun.proxy.$Proxy0
------- before------->
---- GetName
<------- after--------
---- GetAge

 上述userService并不是UserServiceImpl类,而是com.sun.proxy.$Proxy0,它是jvm运行时动态生成的一个对象。

 

2.1 InvocationHandler源码

public static Object newProxyInstance(ClassLoader loader,
									  Class<?>[] interfaces,
									  InvocationHandler h)
	throws IllegalArgumentException
{
	Objects.requireNonNull(h);

	final Class<?>[] intfs = interfaces.clone();
	final SecurityManager sm = System.getSecurityManager();
	if (sm != null) {
		checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
	}

	// 查找或生成代理类
	Class<?> cl = getProxyClass0(loader, intfs);

	/*
	 * Invoke its constructor with the designated invocation handler.
	 */
	try {
		if (sm != null) {
			checkNewProxyPermission(Reflection.getCallerClass(), cl);
		}

		// 通过反射获取构造函数并生成代理实例
		final Constructor<?> cons = cl.getConstructor(constructorParams);
		final InvocationHandler ih = h;
		if (!Modifier.isPublic(cl.getModifiers())) {
			AccessController.doPrivileged(new PrivilegedAction<Void>() {
				public Void run() {
					cons.setAccessible(true);
					return null;
				}
			});
		}
		return cons.newInstance(new Object[]{h});
	} catch (IllegalAccessException|InstantiationException e) {
		throw new InternalError(e.toString(), e);
	}
}

private static Class<?> getProxyClass0(ClassLoader loader,
									   Class<?>... interfaces) {
	if (interfaces.length > 65535) {
		throw new IllegalArgumentException("interface limit exceeded");
	}

	// 查找缓存是否存在,否则通过ProxyClassFactory生成
	return proxyClassCache.get(loader, interfaces);
}

 核心实现在ProxyClassFactory中,该类通过反射方式来构建类。

 

3. 方法二:cglib实现

Java动态代理需实现一个或多个接口,比较麻烦。CGLIB可以在不实现接口前提下,生成代理类。CGLIB 底层通过小而快字节码处理框架ASM来转换字节码并生成新的类。

 

/**
 * CgLib实现动态代理
 * @author lingsun
 *
 */
public class CgLibProxy implements MethodInterceptor{
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		
		if( method.getName() == "getName" ){
			System.out.println( "---------before "+ methodProxy.getSuperName() + "----->");
			Object ol = methodProxy.invokeSuper(obj, args);
			System.out.println( "<---------after "+ methodProxy.getSuperName() + "-----");
			
			return ol;
		}
		else{
			Object ol = methodProxy.invokeSuper(obj, args);
			return ol;
		}
	}
	
	/**
	 * main
	 * asm在内存中动态生成代理类
	 * 注:http://asm.ow2.org/
	 * Spring容器代替工厂,Spring AOP代替JDK动态代理,让面向切面编程更容易实现
	 * 在Spring的帮助下轻松添加,移除动态代理,且对源代码无任何影响
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		CgLibProxy proxy = new CgLibProxy();
		
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass( UserServiceImpl.class);
		enhancer.setCallback(proxy); 	// 设置回调
		
		// 实例通过Enhancer创建
		UserService service = (UserService)enhancer.create();
		System.out.println( "Proxy: " + service );
		
		service.getName();
		service.getAge();
	}
}

 

执行结果:

Proxy: com.jd.proxy.UserServiceImpl$$EnhancerByCGLIB$$a129aaba@41906a77
---------before CGLIB$getName$0----->
---- GetName
<---------after CGLIB$getName$0-----
---- GetAge

 

参考链接:

Java动态代理作用

Java动态代理机制

深入JDK剖析动态代理

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics