java反射学习(2):反射与代理模式

一 基本代理设计模式

代理模式核心思路,一个接口有两个子类,一个子类完成业务需求,另一个完成辅助功能

假设实现一个功能,张三吃饭

代码如下:


接口 PersonDao.java

package com.learing._02;


public interface PersonDao {
	
	public void eat();
	
}

业务类 Person.java

package com.learing._02;

/**
 * 业务类
 * */
public class Person implements PersonDao {
	
	private String name;
	
	public Person(String name) {
		this.name = name;
	} 
	
	@Override
	public void eat(){
		System.out.println(this.name + "吃饭");
	}
}


测试类  Demo.java

package com.learing._02;

public class Demo {
	
	public static void main(String args[]){
		PersonDao zhangsan = new Person("张三");
		zhangsan.eat();
	}
	
}


输出结果



现在增加一个需求,吃饭前要洗手,吃完饭后要洗碗,但是要求不能修改Person任何代码情况下,完成该功能,那么需要一个辅助类来完成了


ProxyPerson.java

package com.learing._02;

public class ProxyPerson implements PersonDao {
	
	private  PersonDao personDao;
	
	public ProxyPerson bind(PersonDao personDao){
		this.personDao = personDao;
		return this;
	}

	@Override
	public void eat() {
		this.beforeEat();
		this.personDao.eat();
		this.afterEat();
		
	}
	
	public void beforeEat(){
		System.out.println("吃饭前要洗手");
	}

	public void afterEat(){
		System.out.println("吃完饭要洗碗");
	}
}

测试类 Demo.java 

package com.learing._02;

public class Demo {
	
	public static void main(String args[]){
		PersonDao zhangsan = new ProxyPerson().bind(new Person("张三")) ;
		zhangsan.eat();
	}
	
}

输出结果



以上就是一个简单代理的代理模式了,Person这个类实现eat()方法, ProxyPerson 这个辅助类实现 "吃饭前要洗手" 和 "吃饭前要洗手"这两个功能,这样

以后要添加什么功能,可以直接在 ProxyPerson代理中增加,而不用改变Person的任何代码,那么这有什么用呢?举个例子,在实际开发中,比如有个删除数据功能,这个功能已经上线很久了,有一天领导说,要增加一个日志功能,那么创建一个辅助类,在这个辅助类中写日志代码,隔了一段时间候,领导又需要增加个某某功能啥的,嘿嘿。。。

但是这里存在一个问题,就是每一个业务类,都必须有一个辅助类(既代理类),假设有100个类都要求有吃饭前洗手和吃完饭后洗碗这两个功能,那么就得写100次,加入又新增了一个晚上7点散步功能,则100个代理类都要新增一个7点散步的功能方法,这简直是一个噩梦啊,可以用JDK动态代理解决该问题.


二 JDK动态代理 (采用反射)

动态代理代码  ProxyPerson.java

package com.learing._02;

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

public class ProxyPerson implements InvocationHandler {
	
	private Object target ; //要代理对象(代替这100个业务类)
	
	public Object bind(Object target){
		this.target = target; 
		//返回与当前传入对象结构相同的代理对象
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
				target.getClass().getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		this.beforeEat();
		Object obj = method.invoke(this.target, args); //采用反射调用 eat()用method代理,并进行调用
		this.afterEat();
		return obj;
	}
	
	public void beforeEat(){
		System.out.println("吃饭前要洗手");
	}

	public void afterEat(){
		System.out.println("吃完饭要洗碗");
	}


}

测试类  Demo.java

package com.learing._02;

public class Demo {
	
	public static void main(String args[]){
		PersonDao zhangsan = (PersonDao) new ProxyPerson().bind(new Person("张三")) ;
		zhangsan.eat();
	}
	
}

输出结果



这里只建了一个类,采用反射,可以替代前面的100多个类,但JDK动态代理存在的问题,就是被代理的对象必须实现接口,而普通对象则不能代理,采用CGLIB对所有类都进行代理.


三 CGLIB动态代理

Person类

package com.learing._02;

/**
 * 业务类
 * */
public class Person{
	
	private String name;
	public Person() {
	
	}
	public void eat(){
		System.out.println("吃饭");
	}
}



CGLIB动态代理代码  CGLIBProxyPerson.java

package com.learing._02;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLIBProxyPerson 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 {
		this.beforeEat();
        proxy.invokeSuper(obj, args);  
        this.afterEat();
        return obj;  
	}
	public void beforeEat(){
		System.out.println("吃饭前要洗手");
	}

	public void afterEat(){
		System.out.println("吃完饭要洗碗");
	}
   
}


测试类 Demo.java

package com.learing._02;

public class Demo {
	
	public static void main(String args[]){
		Person zhangsan = (Person) new CGLIBProxyPerson().getInstance(new Person()) ;
		zhangsan.eat();
	}
	
}

输出结果


采用CGLIB对没有实现接口的普通Person.java类进行代理






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值