目录
静态代理
- 抽象角色:一般使用接口或者抽象类来实现
- 真实角色:被代理的角色
- 代理角色:代理真是角色。代理真实角色后,一般会做一些附属操作
- 客户:使用代理角色来进行一些操作
抽象角色:
/*
* 出租
*/
public interface Rent {
public void rent();
}
真实角色:
/*
* 房东
*/
public class Host implements Rent{
public void rent() {
System.out.println("房东要出租房子!");
}
}
代理角色:
/*
* 代理角色
*/
public class Proxy implements Rent
{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHose();
host.rent();
hetong();
fare();
}
//收中介费
private void fare() {
System.out.println("收取中介费!");
}
private void hetong() {
System.out.println("签租赁合同!");
}
//看房
private void seeHose() {
System.out.println("中介带你看房子!");
}
}
客户:
//客户
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
分析:在这个过程中,我们直接接触的时中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子,通过代理。这就是所谓的代理模式。
静态代理的好处
- 可以使得我们的真实角色更加存粹,不再去关注一些公共的事情
- 公共的业务由代理来完成,实现了业务的分工
- 公共业务发生扩展时变得更加集中和方便
缺点:当类很多的时候,代理类也就多了,工作量变大,使得开发效率降低。
我们想要静态代理的好处,又想解决静态代理的缺点,于是,就有了动态代理。
动态代理
- 动态代理的角色和静态代理的一样
- 动态代理的代理类时动态生成的,静态代理的代理类是我们自己提前写好的
- 动态代理分为两类:
- 基于接口的动态代理 --- JDK动态代理
- 基于类的动态代理 --- cglib
源码:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- ClassLoader:指定的类加载器,把指定代理类的 .class文件加载到内存,形成Class对象
- Class[] interfaces:指定要实现代理类的接口数组
- InvocationHandler:一定要实现的一个接口,它只有一个方法(invoke)要实现,实现方法就是动态代理的具体实现。
public Object invoke(Object proxy, Method method, Object[] args);
- Object proxy:当前对象,即代理对象 在调用谁的方法
- Method method:当前被调用的方法(目标方法)
- Object[] args:方法实参
JDK的动态代理需要了解两个类
核心:InvocationHandler接口 和 Proxy类
- InvocationHandler【调用处理程序】,是由代理实例的调用处理程序实现的接口。
- 每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
- Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理的超类。
UserDao接口,抽象角色:
package com.damin.Demo2;
public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void query();
}
UserDaoImpl,真实角色:
package com.damin.Demo2;
public class UserDaoImpl implements UserDao{
public void add() {
System.out.println("增加");
}
public void delete() {
System.out.println("删除");
}
public void update() {
System.out.println("修改");
}
public void query() {
System.out.println("查找");
}
}
实现接口InvocationHandler 的 MyInvocationHandler 类,代理角色:
package com.damin.Demo2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
//目标对象
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验");
//通过反射里面的method去调用invoke方法,传递了一个目标对象和参数
Object result = method.invoke(target, args);
System.out.println("日志校验");
//返回的就是代理对象
return result;
}
}
Test:
package com.damin.Demo2;
import java.lang.reflect.Proxy;
public class MyTest {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
//我们要创建一个动态代理对象
//Proxy类中有一个方法可以创建动态代理对象
// public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
// InvocationHandler h);
MyInvocationHandler handler = new MyInvocationHandler(userDao);
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(),
handler);
proxy.add();
proxy.delete();
proxy.update();
proxy.query();
}
}
核心:一个动态代理,一般代理某一类业务;一个动态代理可以代理多个类,代理的是接口!