设计模式(3)-结构型-代理模式(proxy)以及java动态代理的两种方式

Fork me on Gitee

HDIS-Framework

fork star

HDIS-Framework是一个基于SpringBoot、Kubernetes、阿里云服务,编写的一个用于支撑微服务的极速开发框架。

其文档详尽,Demo全面,设计合理,开箱即用,节省开发时间,提升开发效率。

配套的docker、Kubernetes教程已踩过各种坑,让你的微服务无障碍的顺畅运行起来。

HDIS与Kubernetes或SpringCloud配合使用,能达到最佳效果。

代理与动态代理

这里只阐述自己对代理与动态代理使用场景的理解,其他的信息自行百度。

代理的使用场景?

例子:事务
在项目中,我的service只想处理与业务相关的逻辑。我并不想在service中显示的嵌入代码去处理事务方面的问题,这样事务就和业务耦合在一起了。但是事务的处理是必不可少的,这个时候就可以使用代理模式,将事务的处理放在代理中,代理处理事务的问题,service处理业务的问题。当程序调用代理的时候,既做了代理做的事,同时代理也调用service做了service该做的事。

代理的定义:为其他对象提供一种代理以控制对这个对象的访问。
可以这样思考,方便理解代理模式的使用场景:
什么时候需要使用AOP什么时候就是需要使用代理模式,AOP所做的事情就是代理模式所关注的事情。
如:权限,事务,日志,数据验证,缓存机制等等。

代理模式的简单实现,便于理解。

//接口
public interface 接口{
    //操作
    publicvoid operation();
}

//实现类
public class 实现类 implement 接口{
    @Override
    public void operation() {
        //一些操作
        System.out.println("一些操作");
    }
}

//代理类
public class 代理类 implement 接口{
    实现类 realObject = new 实现类();
    @Override
    public void operation() {
        //调用目标对象之前可以做相关操作
        System.out.println("before");        
        realObject.operation();        
        //调用目标对象之后可以做相关操作
        System.out.println("after");
    }
}

为什么要使用动态代理?

至于为什么需要使用动态代理,我们从反面设想,不使用动态代理,那么就使用普通代理模式,普通代理模式的特点一对一,一个原始类,一个代理类,如果有N多个原始类,就有N多个代理类,可见原来Jive源码中是这样,结果造成代码琐碎,比如权限代理,要为每个原始类都建立一个其实内部内容都差不多的代理类。

那么动态代理正好解决这个问题,只要建立一个权限动态代理类,就能够为多个原始类进行代理。


JDK实现动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。

如何使用JDK动态代理?

/**
 * 实现自己的InvocationHandler
 */
public class MyInvocationHandler implements InvocationHandler {
	
	// 目标对象 
	private Object target;
	
	/**
	 * 构造方法
	 * @param target 目标对象 
	 */
	public MyInvocationHandler(Object target) {
		super();
		this.target = target;
	}


	/**
	 * 执行目标对象的方法
	 */
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 在目标对象的方法执行之前简单的打印一下
		System.out.println("------------------before------------------");
		// 执行目标对象的方法
		Object result = method.invoke(target, args);
		// 在目标对象的方法执行之后简单的打印一下
		System.out.println("-------------------after------------------");
		return result;
	}

	/**
	 * 获取目标对象的代理对象
	 * @return 代理对象
	 */
	public Object getProxy() {
		return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
				target.getClass().getInterfaces(), this);
	}
}
/**
 * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
 */
public interface UserService {

	/**
	 * 目标方法 
	 */
	public abstract void add();

}
/**
 * 目标对象
 */
public class UserServiceImpl implements UserService {

	public void add() {
		System.out.println("--------------------add---------------");
	}
}
/**
 * 动态代理测试类
 */
public class ProxyTest {

	@Test
	public void testProxy() throws Throwable {
		// 实例化目标对象
		UserService userService = new UserServiceImpl();
		// 实例化InvocationHandler
		MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
		// 根据目标对象生成代理对象
		UserService proxy = (UserService) invocationHandler.getProxy();
		// 调用代理对象的方法
		proxy.add();
		
	}
}

执行结果
------------------before------------------ 
--------------------add--------------- 
-------------------after------------------ 

JDK动态代理实现原理?

具体可参考:http://rejoy.iteye.com/blog/1627405


CGLIB实现动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。
CGLIB是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM(Java字节码操控框架),来转换字节码并生成新的类,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

如何使用CGLIB实现动态代理?

public class BookFacadeImpl {  
    public void addBook() {  
        System.out.println("增加图书的普通方法...");  
    }  
}  
/** 
 * 使用cglib动态代理
 */  
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  
  
    /** 
     * 创建代理对象 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        //设置需要创建子类的类
        enhancer.setSuperclass(this.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("事物开始");
        //通过代理类调用父类中的方法
        proxy.invokeSuper(obj, args);
        System.out.println("事物结束");
        return null;
    }  
  
}  
public class TestCglib {  
      
    public static void main(String[] args) {  
	    //动态代理对象
        BookFacadeCglib cglib=new BookFacadeCglib();  
        //通过生成子类的方式创建代理类
        BookFacadeImpl bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl());  
        //执行代理方法
        bookCglib.addBook();  
    }  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值