什么是代理模式
代理模式:通过代理,控制对对象的访问。可以详细控制某个对象的方法,在调用这个方法前做前置处理,调用者这个方法后做后置处理。核心使用了AOP机制。
AOP支持代理模式吗?
AOP即面向切面编程,它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加一种功能的一种技术,因此AOP能很好的实现代理模式。
常用术语:
切面(Aspect):其实就是共有功能的实现。
通知(Advice):是切面的具体实现。
连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。
切入点(Pointcut):用于定义通知应该切入到哪些连接点上。
目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象
代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。
织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。
代理模式的核心角色
抽象角色:定义代理角色和真实角色的公共对外方法.
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,提供给代理角色调用,只关注真正的业务逻辑。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。(将统一的流程控制放到代理角色中处理)
代理模式的应用场景
- 安全代理:屏蔽对真实角色的直接访问.
- 远程代理:通过代理类处理远程方法的调用(RMI)
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象.
代理模式的实现方式
静态代理
抽象角色:
/*
* 创建被代理角色的抽象角色接口
*/
public interface Star {
/*
* 面谈
*/
void confer();
/*
* 签合同
*/
void signContract();
/*
* 订票
*/
void bookTicket();
/*
* 唱歌
*/
void sing();
/*
* 收钱
*/
void collectMoney();
}
真实角色:
/*
* 这是一个真实角色:明星
*/
public class RealStar implements Star {
public void confer() {
// TODO Auto-generated method stub
}
@Override
public void signContract() {
// TODO Auto-generated method stub
}
public void bookTicket() {
// TODO Auto-generated method stub
}
public void sing() {
// TODO Auto-generated method stub
System.out.println("刘德华在唱歌......");
}
public void collectMoney() {
// TODO Auto-generated method stub
}
}
代理角色:
/*
* 这是一个代理角色,我们希望它把除了唱歌之外的其他事情都代理掉
*/
public class ProxyStar implements Star{
RealStar realstar;
public ProxyStar(RealStar realstar) {
// TODO Auto-generated constructor stub
this.realstar=realstar;
}
@Override
public void confer() {
// TODO Auto-generated method stub
}
@Override
public void signContract() {
// TODO Auto-generated method stub
}
@Override
public void bookTicket() {
// TODO Auto-generated method stub
}
@Override
public void sing() {
// TODO Auto-generated method stub
realstar.sing();
}
@Override
public void collectMoney() {
// TODO Auto-generated method stub
}
}
动态代理
动态代理相比于静态代理的优点:抽象角色中接口声明的所有方法被转移到调用处理器一个集中的方法中处理,这样,我们就可以更加灵活和统一的处理众多的方法.
抽象角色:
/*
* 创建被代理角色的抽象角色接口
*/
public interface Star {
/*
* 面谈
*/
void confer();
/*
* 签合同
*/
void signContract();
/*
* 订票
*/
void bookTicket();
/*
* 唱歌
*/
void sing();
/*
* 收钱
*/
void collectMoney();
}
真实角色:
/*
* 真实角色:明星
*/
public class RealStar implements Star{
@Override
public void confer() {
// TODO Auto-generated method stub
}
@Override
public void signContract() {
// TODO Auto-generated method stub
}
@Override
public void bookTicket() {
// TODO Auto-generated method stub
}
@Override
public void sing() {
// TODO Auto-generated method stub
System.out.println("刘德华在唱歌");
}
@Override
public void collectMoney() {
// TODO Auto-generated method stub
}
}
动态代理:
/*
*
* 使用了java反射实现动态代理,类似AOP的切面编程
*/
public class StarHandler implements InvocationHandler{
Star realstar;
public StarHandler(Star realstar) {
// TODO Auto-generated constructor stub
this.realstar=realstar;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Object object=null;
System.out.println("真正的方法执行前");
if ("sing".equals(method.getName())) {
realstar.sing();
}
System.out.println("真正的方法执行后");
return null;
}
}
代理角色:
/*
* 代理角色
* 通过动态代理判断是否要执行真实角色的方法
*/
public class StarProxy implements Star{
StarHandler handler;
public StarProxy(StarHandler starHandler) {
// TODO Auto-generated constructor stub
this.handler=starHandler;
}
@Override
public void confer() {
// TODO Auto-generated method stub
}
@Override
public void signContract() {
// TODO Auto-generated method stub
}
@Override
public void bookTicket() {
// TODO Auto-generated method stub
}
@Override
public void sing() {
// TODO Auto-generated method stub
}
@Override
public void collectMoney() {
// TODO Auto-generated method stub
}
}
执行代码:
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
//这里很关键,通过反射机制的Proxy类将StarHandler动态代理类切入StarProxy的所有方法中.
//这里可能有人会疑惑,为什么生成的是StarProxy类对象而不是RealStar类对象,因为第三个参数handler决定了调用的是StarProxy的构造器而不是RealStar的构造器
Star proxy=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] {Star.class}, handler);
proxy.bookTicket();
proxy.sing();
}
}