1、静态代理
静态代理由 业务实现类、业务代理类 两部分组成,都实现了业务逻辑接口。
业务实现类 :实现业务逻辑接口,负责实现主要的业务方法。
业务代理类 :持有业务实现类的引用,调用这个引用对象的实现方法来实现业务逻辑接口
负责对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,
然后调用业务实现类的方法,还可以规定调用后的操作。
我们在需要调用业务时,不是直接通过业务实现类来调用的,
而是通过业务代理类的同名方法来调用被代理类处理过的业务方法。
静态代理的实现:
1.1、首先定义一个接口,声明要代理的业务:
public interface Count {
// 查询账户
public void queryCount();
// 修改账户
public void updateCount();
}
1.2、定义业务实现类:
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户...");
}
@Override
public void updateCount() {
System.out.println("修改账户...");
}
}
1.3、定义业务代理类:
public class CountProxy implements Count {
private CountImpl countImpl; //组合一个业务实现类对象来进行真正的业务方法的调用
/**
* 覆盖默认构造器
*
* @param countImpl
*/
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
public void queryCount() {
System.out.println("查询账户的预处理——————");
// 调用真正的查询账户方法
countImpl.queryCount();
System.out.println("查询账户之后————————");
}
@Override
public void updateCount() {
System.out.println("修改账户之前的预处理——————");
// 调用真正的修改账户操作
countImpl.updateCount();
System.out.println("修改账户之后——————————");
}
}
1.4、静态代理使用:
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
静态代理的缺点很明显:
(1)、一个代理类只能对一个业务接口的实现类进行代理,如果有多个业务接口的话就要定义很多实现类和代理类才行。
(2)、如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。
动态代理:解决静态代理的缺点,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。
2、动态代理
通过Proxy.newProxyInstance(loader, interfaces, handler)动态生成代理对象;
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
handler: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
原理:反射机制
2.1、首先定义一个接口:声明要代理的业务:
public interface BookFacade {
public void addBook();
}
2.2、定义业务实现类:
public class BookFacadeImpl implements BookFacade {
@Override
public void addBook() {
System.out.println("增加图书方法。。。");
}
}
2.3、定义一个处理器实现类:每次动态生成代理对象时都需要指定一个处理器对象参数
public class InvocationHandlerImpl implements InvocationHandler {
/**
* 这个就是我们要代理的真实对象
*/
private Object subject;
/**
* 构造方法,给我们要代理的真实对象赋初值
*
* @param subject
*/
public InvocationHandlerImpl(Object subject)
{
this.subject = subject;
}
/**
* 该方法负责集中处理动态代理类上的所有方法调用。
* 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
*
* @param proxy 代理类实例
* @param method 被调用的方法对象
* @param args 调用参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("在调用之前,我要干点啥呢?");
System.out.println("Method:" + method);
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
Object returnValue = method.invoke(subject, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("在调用之后,我要干点啥呢?");
return returnValue;
}
}
2.4、动态代理使用:
当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。
public static void main(String[] args) {
//定义被代理对象
BookFacadeImpl bookFacadeImpl=new BookFacadeImpl();
/**
* InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
* 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用.
* 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
*/
InvocationHandler handler = new InvocationHandlerImpl(bookFacadeImpl);
ClassLoader loader = bookFacadeImpl.getClass().getClassLoader();
Class[] interfaces = bookFacadeImpl.getClass().getInterfaces();
BookFacade bookFacade = (BookFacade) Proxy.newProxyInstance(loader, interfaces, handler);
bookfacade.addBook();
}