代理:就是让代理角色帮助真实角色完成一件事情
静态代理
代理角色和真实角色都需要实现同一个接口
特点:代理类和目标类在代码中是确定的
可以在不修改目标对象功能的前提下,对目标进行扩展.
缺点:不够灵活
动态代理
也叫jdk代理或接口代理,是在程序执行的过程中,通过反射产生的代理对象
JDK动态代理特点:基于接口实现
代理对象的生成是利用JDK的API动态的在内存中构建代理对象
JDK实现代理只需要使用newProxyInstance方法,该方法需要三个参数,语法格式如下:
public static Object newProxyInstance(ClassLoader loader,Class<?>[ ] interfaces,InvocationHandler h)
注意该方法在Proxy类中是静态方法,且接受的三个参数说明分别为:
ClassLoader loader:实现的接口的类加载器
Class<?> [ ] interfaces:基于接口的字节码文件对象数组
InvocationHandler h:是接口InvocationHandler:代理的处理程序,执行目标对象的方法时,把当前执行目标对象的方法作为参数传入
实例介绍静态代理与动态代理
静态代理
定义一个结婚的接口
interface Marry{
void marry();
}
每个人(真实角色)都要结婚,实现Marry接口
Class Person implements Marry{ //真实角色
public void marry();
System.out.println("结婚是一件开心的事情");
}
婚庆公司--代理角色,帮助人完成结婚这件事
class WeddingCompany implements Marry{
//声明一个接口Marry类型变量
private Marry marry;
public WeddingCompany(Marry marry){ //形式参数是一个借口,需要接口子实现类对象
this.marry=marry;
}
public void marry(){
//代理角色需要帮助真实角色完成结婚这件事
System.out.println("结婚前,需要布置婚礼现场");
mary.mary();
System.out.println("婚礼后,需要支付尾款");
}
}
测试代码
public class StaticProxyTest{
public static void main(String [] args){
//使用静态代理
Person person = new Person();
WeddingCompany weddingCompany = new WeddingCompany(person);
weddingCompany.marry();
}
}
动态代理
针对用户访问的数据接口
/**
* 针对用户访问的数据接口
*/
public interface UserDao {
/**
* 添加功能
*/
void add();
/**
* 修改功能
*/
void update();
/**
* 查找功能
*/
void select();
/**
* 删除功能
*/
void delete();
}
针对用户数据访问接口的实现
public class UserDaoImpl implements UserDao{
public void add() {
System.out.println("添加功能");
}
public void update() {
System.out.println("修改功能");
}
public void select() {
System.out.println("查询功能");
}
public void delete() {
System.out.println("删除功能");
}
}
基于代理的处理程序
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 基于代理的处理程序
*/
public class MyInvocation implements InvocationHandler{
//针对谁产生代理 ud UserDao ud = new UserDaoImpl();
private Object target;
public MyInvocation(Object target){
this.target=target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
//调用接口中自己的方法,add(),update(),select(),delete();
//当前实例---->真实角色
Object obj = method.invoke(target, args); //代理角色产生
System.out.println("产生日志文件");
return obj;
}
}
测试代码
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl(); //真实角色
//前提是需要有一个接口
//public static Obejct newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h)
MyInvocation handler = new MyInvocation(ud);
UserDao proxyInstance = (UserDao) Proxy.newProxyInstance(
ud.getClass().getClassLoader(),
ud.getClass().getInterfaces(),
handler);
proxyInstance.add();
proxyInstance.update();
proxyInstance.select();
proxyInstance.delete();
}
}
静态代理和动态代理主要有以下几点区别
- 静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,则代理类需要同步增加,违背开闭原则
- 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则
- 若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码