1、概念
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
2、UML类图
3、java代码实现
抽象角色:表演接口(Act)
public interface Act {
void act();
}
具体角色:演员类(Actor),实现表演接口(Act)
public class Actor implements Act {
private String name;
@Override
public void act() {
System.out.println("我是演员,我会喷火!!!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
代理角色:代理类(StaticProxy),实现表演接口(Act),维护一个表演接口(Act)的引用
public class StaticProxy implements Act {
private Act target;
public StaticProxy(Act target) {
this.target = target;
}
@Override
public void act() {
System.out.println("我是代理人,下面是演员的表演!!!");
target.act();
}
}
测试
@Test
public void testStaticProxy(){
Act target = new Actor();
StaticProxy proxy = new StaticProxy(target);
proxy.act();
}
测试结果
我是代理人,下面是演员的表演!!!
我是演员,我会喷火!!!
以上代码用"代理模式"实现了的一个简单案列,这种代理模式叫做"静态代理",它的一个明显的缺点就是接口发生变化,代理对象的代码也要进行相应的维护。除了"静态代理"外,java还存在其他两种"代理模式",分别是"动态代理"和"Cglib代理"
动态代理(jdk代理或接口代理):目标对象必须实现一个或多个接口
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object newProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (Object proxy, Method method, Object[] args) -> {
System.out.println("动态代理(JDK代理)");
Object returnValue = method.invoke(target, args);
return returnValue;
}
);
}
}
测试及测试结果
@Test
public void testJdkProxy(){
Act target = new Actor();
ProxyFactory factory = new ProxyFactory(target);
Act act = (Act) factory.newProxyInstance();
act.act();
}
动态代理(JDK代理)
我是演员,我会喷火!!!
Cglib代理:无需实现接口
舞者类(Dancer):没有实现任何接口
public class Dancer {
public void dance() {
System.out.println("我是舞者,我会跳舞!!!");
}
}
Cglib代理类
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object newProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理");
Object returnValue = method.invoke(target, objects);
return returnValue;
}
}
测试及测试结果
@Test
public void testCglibProxy() {
Dancer dancer = new Dancer();
CglibProxy cglibProxy = new CglibProxy(dancer);
Dancer proxy = (Dancer) cglibProxy.newProxyInstance();
proxy.dance();
}
Cglib代理
我是舞者,我会跳舞!!!
4、总结
三种代理模式各有优缺点,主要在于目标对象是否实现了接口。
例如:在Spring中,加入容器的目标对象实现了接口,就用jdk代理;没有就用cglib代理。