静态代理与JDK动态代理
代理
生活中的代理:比如帮我们买东西的代购,还有媒婆、中介、商家…都属于代理
静态代理
概念:
1、使用Java文件实现,自己手工实现一个代理类
2、代理目标是确定的
特点:
优点:
1、实现简单
2、容易理解
缺点:
1、当目标类较多时:会产生大量的代理类
2、当接口改变时:影响的目标类较多
实现静态代理的步骤:
1、创建接口,定义方法,表示目标和代理要做的事情。
2、创建目标类,实现接口
3、创建代理类,实现接口(实现了功能的增强)
4、创建客户端类,调用代理进行一个操作。
举例:
//定义一个接口
public interface GoPlay {
void play();
}
//创建目标类、实现接口
public class Basketball implements GoPlay{
@Override
public void play() {
System.out.println("打篮球!");
}
}
//创建代理类,实现接口(实现了功能的增强)
public class GoPlayProxy implements GoPlay{
//声明一个接口GoPlay类型变量
private GoPlay goplay;
public GoPlayProxy(GoPlay goplay){
this.goplay = goplay;
}
@Override
public void play() {
//预处理
System.out.println("预处理");
goplay.play();//执行目标对象的方法
//后置处理
System.out.println("后置处理");
}
}
//创建客户端类,调用代理进行一个操作。
public class StaticProxyDemo {
public static void main(String[] args) {
//创建实际的目标对象
GoPlay goplay = new GoPlay();
//代理对象,把目标对象封装到代理对象中,建立代理关系
GoPlayProxy proxy = new GoPlayProxy(goplay);
proxy.play();
}
}
jdk动态代理
概念:
使用Java反射包中的类和接口实现动态代理的功能。
1、反射,Method类,表示方法。类中的方法,通过Method可以执行某个方法。
2、jdk动态代理的实现
反射包 java.lang.reflect, 里面有三个类:InvocationHandler, Method, Proxy。
特点:
优点:
1、不用创建类文件
2、不用给不同的目标随时创建代理
1、InvocationHandler 接口
中文名:调用处理器
作用:表示代理要做的事
使用方法:
1、创建InvocationHandler接口的实现类
2、重写invoke()方法,把原来静态代理中代理类要完成的功能,写到这个地方
2、invoke()方法:
public Object invoke(Object proxy, Method method, Object[] args)
Object proxy:jdk创建的代理对象,无需赋值
Method method: 目标类中的方法,jdk提供method对象的
object[] args: 目标类中方法的参数
3、Method类:
作用:通过Method可以执行某个目标类的方法,Method.invoke()
Method.invoke(目标对象, 方法的参数)
4、Proxy类:
方法:静态方法:newProxyInstance()
作用:创建代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
ClassLoader loader :类加载器,负责向内存中加载对象的,使用反射获取对象的classLoader。 例如: 类A: A.getClass.getClassLoader(), 主要是为了获取目标对象的类加载器。
Class<?>[] interfaces:接口,目标对象实现的接口,也是反射获取的。
InvocationHandler h:是我们自己写的,代理类要完成的功能。
Object:就是目标对象的代理对象
实现动态代理的步骤:
1、创建接口,定义目标类要完成的功能
2、创建目标类实现接口
3、创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
3.1、调用目标方法
3.2、增强功能
4、使用Proxy类的静态方法,创建代理对象。并把返回值转为接口类型
举例:
/**
* 针对用户访问的数据接口
*/
public interface UserDao {
/**
* 添加功能
*/
void add() ;
/**
* 修改功能
*/
void update() ;
/**
* 查询功能
*/
void select() ;
/**
* 删除功能
*/
void delete() ;
}
/**
* 针对用户数据访问接口的实现
*/
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加功能");
}
@Override
public void update() {
System.out.println("修改功能") ;
}
@Override
public void select() {
System.out.println("查询功能");
}
@Override
public void delete() {
System.out.println("删除功能");
}
}
/**
* 对业务方法 add,update,select.delete进行增强
*/
public class UserDaoImpl2 implements UserDao {
@Override
public void add() {
System.out.println("权限校验") ;
System.out.println("执行添加功能");
System.out.println("产生日志文件");
}
@Override
public void update() {
System.out.println("权限校验") ;
System.out.println("执行修改功能");
System.out.println("产生日志文件");
}
@Override
public void select() {
System.out.println("权限校验") ;
System.out.println("执行查询功能");
System.out.println("产生日志文件");
}
@Override
public void delete() {
System.out.println("权限校验") ;
System.out.println("执行删除功能");
System.out.println("产生日志文件") ;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 基于代理的处理程序
*/
public class MyInvocation implements InvocationHandler {
//要针对谁产生代理:UserDao ud = new UserDaoImpl() ;
private Object target ; //因为代理角色可以是任意Java类型,所
// 以用Object
public MyInvocation(Object target){
this.target = target ;
}
//方法的返回值就是代理对象
@Override //就是我们的接口的方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验") ;
//调用接口的列表自己的方法:update(),delete(),add(),select()
//当前实例--->真实角色
Object obj = method.invoke(target, args); //代理角色产生
System.out.println("产生日志文件");
return obj;
}
}
/**
* Jdk动态代理:
* 是在程序的执行过程中,通过反射产生的代理对象!
* java.lang.reflect.Proxy
* jdk动态代理特点:
* 基于接口实现的
* cglib动态代理
* 基于类实现
*
* Proxy
* public static Object newProxyInstance(ClassLoader loader, 参数1:实现的接口的类加载器
* Class<?>[] interfaces, 参数2:基于接口的字节码文件对象数组
* InvocationHandler h) 参数3:是接口InvocationHandler :代理的处理程序
*
* throws IllegalArgumentException
*
* 参数3是一个接口:自定一个类实现这个接口
* 重写这个接口中的
* Object invoke(Object proxy,Method method,Object[] args)throws Throwable
*/
public class JdkProxyDemo {
public static void main(String[] args) {
//接口多态:测试UserDao
UserDao ud = new UserDaoImpl() ; //真实角色
//版本1:现在需要对功能增强,这个代码不合适!
ud.add();
ud.update();
ud.select();
ud.delete();
System.out.println("----------------------------------");
UserDao ud2 = new UserDaoImpl2() ;
ud2.add();
ud2.update();
ud2.select();
ud2.delete();
System.out.println("----------------Jdk动态代理------------------");
//前提是需要一个接口:UserDao
MyInvocation handler = new MyInvocation(ud) ;
// public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
UserDao proxyInstance = (UserDao) Proxy.newProxyInstance(
ud.getClass().getClassLoader(),
ud.getClass().getInterfaces(),
handler);
proxyInstance.add();
proxyInstance.update();
proxyInstance.select();
proxyInstance.delete();
}
}