JDK动态代理(一)

介绍       

代理模式
        代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。 

        在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

一)静态代理: 

1.Count.java

package net.battier.dao;  
/**  
 * 定义一个账户接口  
 *   
 * @author Administrator  
 *   
 */   
public interface Count {   
    // 查看账户方法   
    public void queryCount();   
    // 修改账户方法   
    public void updateCount();    
}   
2.CountImpl.java

package net.battier.dao.impl;   
import net.battier.dao.Count;   
/**  
 * 委托类(包含业务逻辑)  
 *   
 * @author Administrator  
 *   
 */   
public class CountImpl implements Count {
    @Override   
    public void queryCount() {   
        System.out.println("查看账户方法...");   
    }   
    @Override   
    public void updateCount() {   
        System.out.println("修改账户方法...");   
    }   
}   
3.CountProxy.java  

package net.battier.dao.impl;   
   
import net.battier.dao.Count;   
   
/**  
 * 这是一个代理类(增强CountImpl实现类)  
 *   
 * @author Administrator  
 *   
 */   
public class CountProxy implements Count {   
    private CountImpl countImpl;   
   
    /**  
     * 覆盖默认构造器  
     *   
     * @param countImpl  
     */   
    public CountProxy(CountImpl countImpl) {   
        this.countImpl = countImpl;   
    }   
   
    @Override   
    public void queryCount() {   
        System.out.println("事务处理之前");   
        // 调用委托类的方法;   
        countImpl.queryCount();   
        System.out.println("事务处理之后");   
    }   
   
    @Override   
    public void updateCount() {   
        System.out.println("事务处理之前");   
        // 调用委托类的方法;   
        countImpl.updateCount();   
        System.out.println("事务处理之后");   
   
    }   
   
}

4.TestCount.java

Java代码 
package net.battier.test;   
import net.battier.dao.impl.CountImpl;   
import net.battier.dao.impl.CountProxy;   
/**  
 *测试Count类  
 *   
 * @author Administrator  
 *   
 */   
public class TestCount {   
    public static void main(String[] args) {   
        CountImpl countImpl = new CountImpl();   
        CountProxy countProxy = new CountProxy(countImpl);   
        countProxy.updateCount();   
        countProxy.queryCount();   
    }   
}  
       观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

二)动态代理

1.定义一个接口和实现 

package com.tech.service;
public interface PersonService {
	public String getPersonName(Integer personId);
	public void save(String name);
	public void update(Integer personId, String name);
}

package com.tech.service.impl;
import com.tech.service.PersonService;
public class PersonServiceBean implements PersonService {	
	public String user = null;

	public PersonServiceBean(){};
	public PersonServiceBean(String user){
		this.user = user;
	}
	
	@Override
	public String getPersonName(Integer personId) {
		// TODO Auto-generated method stub
		System.out.println("这是find方法");
		return this.user;
	}

	@Override
	public void save(String name) {
		// TODO Auto-generated method stub
		System.out.println("这是save方法");
	}

	@Override
	public void update(Integer personId, String name) {
		// TODO Auto-generated method stub
		System.out.println("这是update方法");
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}

}
2.JDK动态代理代理类

package com.tech.jdkproxy;

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

import com.tech.service.impl.PersonServiceBean;

/**
 *  
 * 切面  
 * @author ch
 *
 */
public class JDKProxyFactory implements InvocationHandler{

	private Object proxyObject; //目标对象

	/**
	 * 绑定委托对象并返回一个代理类 
	 * @param proxyObject
	 * @return
	 */
	public Object createProxyInstance(Object proxyObject) {
		this.proxyObject = proxyObject;
		
		//生成代理类的字节码加载器 
		ClassLoader classLoader = proxyObject.getClass().getClassLoader();
		//需要代理的接口,被代理类实现的多个接口都必须在这里定义  (这是一个缺陷,cglib弥补了这一缺陷)  
	    Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();//new Class[]{}; 
	    
	    //织入器,织入代码并生成代理类   
		return Proxy.newProxyInstance(classLoader,
				proxyInterface, this);

	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		PersonServiceBean bean = (PersonServiceBean)this.proxyObject;
		Object result = null;
		//控制哪些用户执行切入逻辑
		if(bean.getUser() != null) {
			//执行原有逻辑   
			result = method.invoke(this.proxyObject, args);
		}
		return result;
	}
}
3.测试类

package com.tech.junit;

import org.junit.BeforeClass;
import org.junit.Test;

import com.tech.jdkproxy.JDKProxyFactory;
import com.tech.service.PersonService;
import com.tech.service.impl.PersonServiceBean;

public class PersonTest {

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@Test
	public void Test() {
		JDKProxyFactory factory = new JDKProxyFactory();
		PersonService bean = (PersonService) factory
				.createProxyInstance(new PersonServiceBean("lucy"));
		//用户为lucy,有权限
		bean.save("abc");
		
		PersonService bean2 = (PersonService) factory
			.createProxyInstance(new PersonServiceBean());
		//用户为null,没有权限,不输出
		bean2.save("abc");
	}
}

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 可以参考另一篇文章cglib动态代理介绍(一)

阅读更多
个人分类: J2SE
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭