码迷,mamicode.com
首页 > 其他好文 > 详细

(4)代理模式

时间:2016-07-23 07:37:44      阅读:319      评论:0      收藏:0      [点我收藏+]

标签:spring


1、概述

代理(Proxy)是一种设计模式, 提供了对目标对象(target)另外的访问方式;即通过代理(proxy)访问目标对象(target)。 

这样的好处: 可以在目标对象(target)实现的基础上,增强额外的功能操作。(扩展目标对象的功能)。

举例:明星<---经纪人<-------用户

技术分享

代理模式的关键点: 代理对象目标对象

2、静态代理

静态代理要求:代理对象(proxy)要实现与目标对象(target)一样的接口。


IUserDao.java

package com.rk.hibernate.a_static_proxy;

public interface IUserDao
{
	void save();
}

UserDao.java

package com.rk.hibernate.a_static_proxy;

public class UserDao implements IUserDao
{

	@Override
	public void save()
	{
		System.out.println("保存数据成功!");
	}

}

UserDaoProxy.java

package com.rk.hibernate.a_static_proxy;

/**
 * 代理对象(静态代理)
 * 	   代理对象,要实现与目标对象一样的接口
 *
 */
public class UserDaoProxy implements IUserDao
{
	// 接收保存目标对象
	private IUserDao target;
	public UserDaoProxy(IUserDao target)
	{
		super();
		this.target = target;
	}


	@Override
	public void save()
	{
		System.out.println("开始事务...");
		
		target.save(); 			// 执行目标对象的方法
		
		System.out.println("提交事务...");

	}

}

App.java

package com.rk.hibernate.a_static_proxy;

import org.junit.Test;

public class App
{
	@Test
	public void save()
	{
//		IUserDao userDao = new UserDao();
//		userDao.save();
		
		// 目标对象
		IUserDao userDao = new UserDao();
		// 代理
		IUserDao proxy = new UserDaoProxy(userDao);
		proxy.save(); // 执行的是,代理的方法
	}
}

 

静态代理总结:

1)可以做到在不修改目标对象的功能前提下,对目标对象功能扩展。

2)缺点:

-->因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多。

-->一旦接口增加方法,目标对象与代理对象都要维护。

缺点的解决办法:使用代理工厂,也可以使用动态代理。

 

3、动态代理(JDK代理)

可以参考:http://lsieun.blog.51cto.com/9210464/1828982


1)代理对象(proxy)不需要实现接口,但是目标对象(target)一定要实现接口;否则不能用动态代理!;

2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型;);

3) 动态代理,也称为“JDK代理”、“接口代理”。


IUserDao.java

package com.rk.hibernate.b_dynamic_proxy;

public interface IUserDao
{
	void save();
}

UserDao.java

package com.rk.hibernate.b_dynamic_proxy;

public class UserDao implements IUserDao
{

	@Override
	public void save()
	{
		System.out.println("保存数据成功!");
	}

}

ProxyFactory.java

package com.rk.hibernate.b_dynamic_proxy;

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

/**
 * 给所有的dao创建代理对象【动态代理】
 * 
 * 代理(proxy)对象,不需要实现接口,而被代理的对象(target)需要实现接口
 *
 */
public class ProxyFactory
{
	// 维护一个目标对象
	private Object target;
	public ProxyFactory(Object target)
	{
		super();
		this.target = target;
	}
	
	// 给目标对象,生成代理对象  
	public Object getProxyInstance()
	{
		return Proxy.newProxyInstance(
							target.getClass().getClassLoader(), 
							target.getClass().getInterfaces(), 
							new InvocationHandler()
							{
								
								@Override
								public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
								{
									System.out.println("开启事务");
									
									// 执行目标对象方法
									Object returnValue = method.invoke(target, args);
									
									System.out.println("提交事务");
									return returnValue;
								}
							});
	}
}

App.java

package com.rk.hibernate.b_dynamic_proxy;

import org.junit.Test;

public class App
{
	@Test
	public void save()
	{
		// 目标对象
		IUserDao target = new UserDao();
		// 【原始的类型 class com.rk.hibernate.b_dynamic_proxy.UserDao】
		System.out.println(target.getClass());
		System.out.println("-------------------------分隔线---------------------------------");
		
		// 给目标对象,创建代理对象
		IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
		// class com.sun.proxy.$Proxy4   内存中动态生成的代理对象
		System.out.println(proxy.getClass());
		
		// 执行方法   【代理对象】
		proxy.save(); 
	}
}


 

动态代理总结:

代理对象(proxy)不需要实现接口,但是目标对象(target)一定要实现接口;否则不能用动态代理!

生成代理类的命名是以“$Proxy”开头。

思考:

有一个目标对象,想要功能扩展,但目标对象没有实现接口,怎样功能扩展?以子类的方式实现(cglib代理)。


 

4、CGLIB代理

Cglib代理,也叫做子类代理,是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。

CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。


UserDao.java

package com.rk.hibernate.c_cglib_proxy;

public class UserDao
{
	public void save()
	{
		System.out.println("保存数据成功!");
	}
}

ProxyFactory.java

package com.rk.hibernate.c_cglib_proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class ProxyFactory implements MethodInterceptor
{
	// 维护目标对象
	private Object target;	
	public ProxyFactory(Object target)
	{
		super();
		this.target = target;
	}
	
	// 给目标对象创建代理对象
	public Object getProxyInstance()
	{
		//1. 工具类
		Enhancer en = new Enhancer();
		//2. 设置父类
		en.setSuperclass(target.getClass());
		//3. 设置回调函数
		en.setCallback(this);
		//4. 创建子类(代理对象)
		return en.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
	{
		System.out.println("开始事务.....");
		
		// 执行目标对象的方法
		Object returnValue = method.invoke(target, args);
		
		System.out.println("提交事务.....");
		
		return returnValue;
	}

}

App.java

package com.rk.hibernate.c_cglib_proxy;

import org.junit.Test;

public class App
{
	@Test
	public void test()
	{
		// 目标对象
		UserDao target = new UserDao();
		// class com.rk.hibernate.c_cglib_proxy.UserDao
		System.out.println(target.getClass());
		
		// 代理对象
		UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
		// UserDao子类:class com.rk.hibernate.c_cglib_proxy.UserDao$$EnhancerByCGLIB$$9531189d
		System.out.println(proxy.getClass());
		
		// 执行代理对象的方法
		proxy.save();
	}
}


 

Cglib子类代理:

1) 需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。

2)引入功能包后,就可以在内存中动态构建子类

3)代理的类不能为final, 否则报错。

4)目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法。




在Spring的AOP编程中,

如果加入容器的目标对象有实现接口,用JDK代理;

如果目标对象没有实现接口,用Cglib代理;


(4)代理模式

标签:spring

原文地址:http://lsieun.blog.51cto.com/9210464/1828984

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!