静态代理
1.简介
代理模式(Proxy Pattern)是GoF 23种Java常用设计模式之一。代理模式的定义:Provide a surrogate or placeholder for another object to controlaccess to it(为其他对象提供一种代理以控制对这个对象的访问)。使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能。
2.比喻
现实世界中,秘书就相当于一个代理,老板开会,那么通知员工开会时间、布置会场、会后整理会场等等开会相关工作就可以交给秘书做,老板就只需要开会就行了,不需要亲自做那些事。同理,在我们程序设计中也可使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。
3.代码实例
定义买接口:
public interface Buy {
void buy();
}
定义people类,作为被代理对象:
public class People implements Buy{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void buy() {
System.out.println(name + "buying!");
}
}
创建代理对象PeopleProxy:
public class PeopleProxy implements Buy{
public PeopleProxy(People people) {
super();
this.people = people;
}
private People people;
@Override
public void buy() {
// 可以做其他事情
System.out.println("代理来买东西");
people.buy();
}
}
主程序:
public class Main {
public static void main(String[] args) {
People p1 = new People();
p1.setName("lyt");
PeopleProxy proxy = new PeopleProxy(p1);
proxy.buy();
}
}
运行结果:
代理来买东西
lytbuying!
由以上可以看出,实际需要调用的是People类的Buy()方法,现在用PeopleProxy类来代理People类,同样达到目的,同时还可以做其他的动作。
动态代理
1.作用
观察静态代理可以发现,每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
即一个代理完成多个接口。
2.原理
根据Java的反射机制动态生成。
3.代码
两个接口:
public interface Buy {
void buy()
}
public interface buyALot {
void buyALot();
}
被代理者:
public class People implements Buy , buyALot{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void buy() {
// TODO Auto-generated method stub
System.out.println(name + " buying!");
}
@Override
public void buyALot() {
// TODO Auto-generated method stub
System.out.println(name + " buying a lot!");
}
}
动态代理:
public class PeopleProxy implements InvocationHandler {
private Object people;
public PeopleProxy(Object people){
this.people=people;
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
// TODO Auto-generated method stub
//调用之前
doBefore();
Object object=arg1.invoke(people, arg2);//普通的Java反射代码,通过反射执行某个类的某方法
//调用之后
doAfter();
return object;
}
private void doBefore(){
System.out.println("before method invoke");
}
private void doAfter(){
System.out.println("after method invoke");
}
}
主程序:
public class Main {
public static void main(String[] args) {
People p1 = new People();
p1.setName("lyt");
InvocationHandler ih=new PeopleProxy(p1);//代理实例的调用处理程序。
Buy buyProxy = (Buy)Proxy.newProxyInstance(p1.getClass().getClassLoader(), p1.getClass().getInterfaces(),ih);
buyProxy.buy();
buyALot buyAlotProxy = (buyALot)Proxy.newProxyInstance(p1.getClass().getClassLoader(), p1.getClass().getInterfaces(),ih);
buyAlotProxy.buyALot();
}
}
运行结果:
before method invoke
lyt buying a lot!
after method invoke
可看到,被代理的方法调用灰进入invoke方法中,我们可以在dobefore和doafter方法中做很多事情。
动态代理的核心代码:
1.动态代理要求必须有接口实现。
2.自己编写Handler类(实现InvocationHandler接口)
3.使用时,用Proxy的newProxyInstance()方法来获取动态代理对象。