一 基本代理设计模式
代理模式核心思路,一个接口有两个子类,一个子类完成业务需求,另一个完成辅助功能
假设实现一个功能,张三吃饭
代码如下:
接口 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 + "吃饭");
}
}
package com.learing._02;
public class Demo {
public static void main(String args[]){
PersonDao zhangsan = new Person("张三");
zhangsan.eat();
}
}
输出结果
现在增加一个需求,吃饭前要洗手,吃完饭后要洗碗,但是要求不能修改Person任何代码情况下,完成该功能,那么需要一个辅助类来完成了
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();
}
}
输出结果