`
JavaCrazyer
  • 浏览: 2994446 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类

Spring温习(4)--静态代理和动态代理

阅读更多

代理模式分为静态代理和动态代理。静态代理就是我们自己定义的代理类,动态代理是程序在运行时生成的代理类。

静态代理示例

Service.java

package com.javacrazyer.dao;

public interface Service {
	public void outPut();
	public void putOut();
}

ServiceImpl.java

package com.javacrazyer.dao;

public class ServiceImpl implements Service {

	@Override
	public void outPut() {
		System.out.println("I am method outPut");
	}

	@Override
	public void putOut() {
		System.out.println("I am method putOut.");
	}

}

 至于上面两个类大家随便举例子,无论是增删改还是什么都可以的

测试类TestProxy.java

package com.javacrazyer.dao;

public class TestProxy {
	public static void main(String[] args) {
		  Service serviceImp = new ServiceImpl();
		  serviceImp.outPut();
		  serviceImp.putOut();
	}

}

 如我们所想,理所当然的输出了

I am method outPut
I am method putOut

下面我们需要加入安全性检查,就是调用方法前我们需要进行验证,比较常见的就是权限验证,验证用户是否拥有权限,

比较常见的做法就是在ServiceManagerImplProxy类中定义一个检查安全性的方法:

好了,这样一说,又得出现一个ServiceManagerImplProxy.java

package com.javacrazyer.dao;


public class ServiceManagerImplProxy implements Service {

	private Service service;
	public ServiceManagerImplProxy(Service service){
		this.service=service;
	}
	
	@Override
	public void outPut() {
		//在调用方法前调用验证方法
	   this.checkSecurity();
       this.service.outPut();
	}

	@Override
	public void putOut() {
		//在调用方法前调用验证方法
		this.checkSecurity();
		this.service.putOut();
	}
	public void checkSecurity()   
    {   
        System.out.println("--------ServiceManagerImpl.checkSecurity()----------");   
    } 

}

 修改下测试代码

package com.javacrazyer.dao;

public class TestProxy {
	public static void main(String[] args) {
		  ServiceManagerImplProxy serviceImp = new ServiceManagerImplProxy(new ServiceImpl());
		  serviceImp.outPut();
		  serviceImp.putOut();
	}

}

 

输出结果

--------ServiceManagerImpl.checkSecurity()----------
I am method outPut
--------ServiceManagerImpl.checkSecurity()----------
I am method putOut

这样总的来说比较灵活。这个依赖关系是我们自己做的,我们完全可以交给spring处理。

按照上面的这种做法有一个缺点,如果接口中方法很多,那么我们实现每一个方法都要添加检查方法checkSecurity(),影响了我们的业务处理。采用静态代理模式我们是没法解决的,这时我们需要使用AOP思想。【AOP底层原理就是动态代理和反射机制】

 

动态代理示例

     使用动态代理我们需要声明一个类SecurityHandler,那么之前的ServiceManagerImplProxy类就不需要了,这个类要实现InvocationHandler接口。在类中定义一个产生动态代理的方法newProxy();同时把我们验证的代码放到这个类中。通过SecurityHandler,当我们调用方法时默认会调用SecurityHandler类invoke方法,我们在这个方法中进行安全性检查,检查通过后在调用真实的方法。需要注意的是目标对象接口中的部分方法是存在返回值的。

SecurityHandler.java

package com.javacrazyer.dao;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理的处理类: 只针对实现了接口的类才能创建出它的代理对象
 * @author cheneywu
 *
 */
public class SecurityHandler implements InvocationHandler {

	private Object originalObject;

	// 将欲代理的对象传入,返回一个代理对象
	public Object newProxy(Object obj) {
		this.originalObject = obj;

		// 三个参数,第一个是欲代理对象的类加载器,第二个是得到这个类的接口集合,第三个参数是一个handler
		return (Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this));
	}

	// 对欲代理对象的方法的调用将会调用这个代理对象的invoke方法
	// 第一个参数是这个代理对象,第二个参数是欲代理对象实现方法,第三个是方法的参数集合
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		checkSecurity();
		// 若方法名以out开头则调用下面逻辑
		if (method.getName().startsWith("out")) {
			System.out.println("This is a method invoking before the method that was intercepted.");
			// 调用欲代理对象的相应方法
			method.invoke(originalObject, args);
			
			System.out.println("This is a method invoking after the method that was intercepted.");
		} else {
			// 若不是需要拦截的方法则正常执行方法
			method.invoke(originalObject, args);
		}
		return null;
	}

	public void checkSecurity()   
    {   
        System.out.println("--------ServiceManagerImpl.checkSecurity()----------");   
    } 

}

 输出结果

--------ServiceManagerImpl.checkSecurity()----------
This is a method invoking before the method that was intercepted.
I am method outPut
This is a method invoking after the method that was intercepted.
--------ServiceManagerImpl.checkSecurity()----------
I am method putOut

跟预期效果一致,

 

使用这种方式维护起来相对比较好,我想进行安全性检查就进行,不想就不进行,很方便。

 

4
0
分享到:
评论
2 楼 liu2511981 2011-05-20  
很好。。。。。我也想看到动态代理的全部实现。



怎么调用的,实际中怎么用的?
1 楼 grossofans 2010-11-09  
初学者,可不可以把 动态代理示例 全部的实现贴出来。

相关推荐

Global site tag (gtag.js) - Google Analytics