代理模式概念
代理模式示例图
静态代理
- 代理对象和目标对象的共同接口
package com.proxy;
public interface Teacher {
public void teach();
}
- 目标对象
package com.proxy;
public class Teacher_1 implements Teacher{
@Override
public void teach() {
System.out.println("老师正在上课");
}
}
- 代理对象
package com.proxy;
public class Teacher_1_proxy implements Teacher {
public Teacher teacher;
public Teacher_1_proxy(Teacher teacher) {
this.teacher = teacher;
}
@Override
public void teach() {
System.out.println("代理开始");
teacher.teach();
System.out.println("代理结束");
}
}
- 客户端
package com.proxy;
public class Client {
public static void main(String[] args) {
Teacher teacher = new Teacher_1();
Teacher_1_proxy teacher_1_proxy = new Teacher_1_proxy(teacher);
teacher_1_proxy.teach();
}
}
静态代理优缺点
动态代理
示例:
待实现的接口:
package com.jdk;
public interface Teacher {
public void teach(String name,int age);
public void rest();
}
接口的具体实现类:
package com.jdk;
public class TargetTeacher implements Teacher{
@Override
public void teach(String name,int age) {
System.out.println(name+"开始授课"+",她的年龄是"+age);
}
@Override
public void rest() {
System.out.println("老师休息");
}
public void newTeach(String name,int age) {
System.out.println(name+"开始授课"+",她的年龄是"+age+",新teach");
}
}
代理工厂,用于生成代理类:
package com.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理工厂,用于生成代理对象
public class ProxyFactory {
//用于代理的目标对象
public Object target;
public ProxyFactory(Object o) {
this.target = o;
}
//获取代理对象的方法
public Object getProxy() {
/*
1.第一个参数:目标对象的类加载器
2.第二个参数:目标对象实现的接口
3.第三个参数:InvocationHandler接口,代理对象的实际的代理过程,即添加额外功能和调用目标对象方法的地方
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
/*
1.proxy:代理对象
2.method:代理对象要执行的方法的描述,这个参数传入的是抽象接口中的方法
3.args:代理对象执行的方法传入的实际参数,这个参数是要作为method中描述的方法的传入参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象:"+proxy.getClass());
System.out.println("方法:"+method.getDeclaringClass().getName()+","+method.getClass());
for(Object o:args) {
System.out.print(o.toString()+",");
}
System.out.println("开始代理");
//触发具体实现类中的的method描述的方法,args作为参数传入
Object returnval = method.invoke(target,args);
return returnval;
}
});
}
}
测试类:
package com.jdk;
import java.lang.reflect.Field;
public class Client {
public static void main(String[] args) {
Teacher t = new TargetTeacher();
ProxyFactory proxyFactory = new ProxyFactory(t);
/*这里不能强制转换成接口的实现类,必须是接口,这是因为代理类实现了接口,
所以返回的代理对象其实是接口的"子对象",因此代理对象不能执行接口实现类的特有方法
TargetTeacher proxy = (TargetTeacher) proxyFactory.getProxy();
proxy.newTeach("fan",22);会执行出错
*/
Teacher proxy = (Teacher) proxyFactory.getProxy();
proxy.teach("fan",22);
//proxy.rest();
}
}
动态代理的执行过程:
- 动态代理类是在程序运行时生成的,其继承了Proxy类并且实现了目标对象实现的接口
- 代理类利用反射机制生成了四个Method对象,这四个对象分别是equals,hashCode,toString和代理类将要执行的方法的描述信息。
- 代理类重写上述四个方法,重写过程是调用父类Proxy中的invoke方法,并将对应的Method对象作为参数传入。
详细过程请参考下面相关链接。
相关参考:
反射及动态代理原理
cglib代理
示例:
目标对象类:
package com.cglib;
public class TeacherDao {
public void teach(){
System.out.println("我是cglib");
}
}
生成代理对象的类:
package com.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyFactory implements MethodInterceptor {
//目标对象,被代理的对象
private Object target;
public ProxyFactory(Object o) {
this.target = o;
}
//返回代理对象
public Object getProxy() {
//1.创建工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4、创建子类对象,即代理对象
return enhancer.create();
}
@Override
//方法拦截器,当调用方法时就会对方法进行拦截
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("代理开始");
Object returnval = method.invoke(target,args);
System.out.println("代理结束");
return returnval;
}
}
测试类:
package com.cglib;
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao = new TeacherDao();
ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
TeacherDao t = (TeacherDao) proxyFactory.getProxy();
//调用方法时会被拦截,从而执行拦截器中的代码
t.teach();
}
}