代理模式(Proxy pattern):
- 核心作用: 通过代理,控制对对象的访问! 可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后 做后置处理。(即:AOP的微观实现!)
- AOP(Aspect Oriented Programming面向切面编程)的核心实现机制!
- 核心角色:
抽象角色 – 定义代理角色和真实角色的公共对外方法
真实角色 – 实现抽象角色,定义真实角色所要实现的业务逻辑, 供代理角色调用, 关注真正的业务逻辑!
代理角色 – 实现抽象角色,是真实角色的代理,通过真实角色 的业务逻辑方法来实现抽象方法,并可以附加 自己的操作。
- 分 类:
– 静态代理(静态定义代理类)
– 动态代理(动态生成代理类)
• JDK自带的动态代理
• javaassist字节码操作库实现
• CGLIB
1、静态代理
以游戏为例
/**
* 抽象角色:游戏
* @author Administrator
*/
public interface IGame {
/**
* 登录
* @param username
* @param password
*/
void login(String username,String password);
/**
* 打怪
*/
void killBoss();
/**
* 升级
*/
void upGrade();
}
/**
* 真实角色:玩家
* @author Administrator
*/
public class GamePlayer implements IGame{
private String name;
public GamePlayer(String name){
this.name=name;
}
@Override
public void login(String username, String password) {
System.out.println("登录名:"+username+"登录成功/n"+"欢迎玩家:"+this.name);
}
@Override
public void killBoss() {
System.out.println(this.name+"在打怪。。。");
}
@Override
public void upGrade() {
System.out.println(this.name+"升了一级。。。");
}
}
/**
* 代理角色:游戏代练
* @author Administrator
*/
public class GamePlayProxy implements IGame{
//被代理对象、真实对象
private GamePlayer gamePlayer;
//通过构造方法注入真实被代理对象
public GamePlayProxy(GamePlayer gamePlayer){
this.gamePlayer=gamePlayer;
}
@Override
public void login(String username, String password) {
System.out.println("代理开始登录。。。");
this.gamePlayer.login(username, password);
System.out.println("代理登陆成功。。。");
}
@Override
public void killBoss() {
System.out.println("代理操作账号打boss。。。");
this.gamePlayer.killBoss();
}
@Override
public void upGrade() {
System.out.println("代理打完boss,升了一级");
this.gamePlayer.upGrade();
System.out.println("代理找玩家收费");
}
}
/**
* 测试
* @author Administrator
*/
public class Client {
public static void main(String[] args) {
//代理出场
IGame gamePlayerProxy = new GamePlayerProxy(new GamePlayer("雄霸天下"));
//登录
gamePlayerProxy.login("admin", "888888");
//打boss
gamePlayerProxy.killBoss();
//升级
gamePlayerProxy.upGrade();
}
}
//输出结果
代理开始登录。。。
登录名:admin登录成功
欢迎玩家:雄霸天下
代理登陆成功。。。
代理操作账号打boss。。。
雄霸天下在打怪。。。
代理打完boss,升了一级
雄霸天下升了一级。。。
代理找玩家收费
2、JDK自带的动态代理
抽象角色和真实角色跟上面静态代理一样,在这就不重复写了
/**
* 万能代理类:JDK自带的动态代理,要实现InvocationHandler
* @author Administrator
*
*/
public class DynamicProxy implements InvocationHandler{
//被代理对象、真实对象
private Object realObj;
//通过构造函数传入一个真实对象
public DynamicProxy(Object realObj) {
this.realObj = realObj;
}
//代理核心,反射调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理对象之前可以做的事情。。。。。");
//真实对象的方法反射调用
Object result=method.invoke(this.realObj, args);
System.out.println("代理对象之后可以做的事情。。。。。");
return result;
}
/**
* 对外提供得到代理对象的实例(动态代理对象)
* @return
*/
public Object getProxyInstance(){
//JDK自带的Proxy类的方法得到实例。
//三个参数分别为:真实对象的类加载器、真实对象的接口、实现InvocationHandler的代理类
Object newProxyInstance = Proxy.newProxyInstance(this.realObj.getClass().getClassLoader(), this.realObj.getClass().getInterfaces(), this);
return newProxyInstance;
}
}
/**
* 测试
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) {
//代理出场
DynamicProxy proxy = new DynamicProxy(new GamePlayer("雄霸天下"));
//得到代理实例返回的是接口,强转
IGame gamePlayer=(IGame)proxy.getProxyInstance();
//登录
gamePlayer.login("admin", "888888");
//打boss
gamePlayer.killBoss();
//升级
gamePlayer.upGrade();
}
}
//输出结果
代理对象之前可以做的事情。。。。。
登录名:admin登录成功
欢迎玩家:雄霸天下
代理对象之后可以做的事情。。。。。
代理对象之前可以做的事情。。。。。
雄霸天下在打怪。。。
代理对象之后可以做的事情。。。。。
代理对象之前可以做的事情。。。。。
雄霸天下升了一级。。。
代理对象之后可以做的事情。。。。。
3、CgLib动态代理(最好的新建maven项目导包)
真是对象不需要再实现接口
/**
* 真实角色:玩家
* @author Administrator
*/
public class GamePlayer {
private String name;
public GamePlayer(String name){
this.name=name;
}
public void login(String username, String password) {
System.out.println("登录名:"+username+"登录成功\n"+"欢迎玩家:"+this.name);
}
public void killBoss() {
System.out.println(this.name+"在打怪。。。");
}
public void upGrade() {
System.out.println(this.name+"升了一级。。。");
}
}
/**
* CgLib动态代理要去实现MethodInterceptor
* @author Administrator
*
*/
public class CgLibProxy implements MethodInterceptor{
//被代理对象、真实对象
private Object realObj;
//通过构造函数传入一个真实对象
public CgLibProxy(Object realObj) {
this.realObj = realObj;
}
//Cglib代理核心,反射调用
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理对象之前可以做的事情。。。。。");
//真实对象的方法反射调用
Object result=method.invoke(this.realObj, args);
System.out.println("Cglib代理对象之后可以做的事情。。。。。");
return result;
}
/**
* 对外提供得到代理对象的实例(动态代理对象)
* @return
*/
public Object getProxyInstance(){
//1、创建Enhancer工具类实例
Enhancer enhancer=new Enhancer();
//2、加载真实类
enhancer.setSuperclass(this.realObj.getClass());
//3、设定MethodInterceptor的实现
enhancer.setCallback(this);
return enhancer;
}
}
/**
* 测试
* @author Administrator
*
*/
public class Client {
public static void main(String[] args) {
//代理出场
CgLibProxy proxy = new CgLibProxy(new GamePlayer("雄霸天下"));
GamePlayer gamePlayer=(GamePlayer)proxy.getProxyInstance();
//登录
gamePlayer.login("admin", "888888");
//打boss
gamePlayer.killBoss();
//升级
gamePlayer.upGrade();
}
}
//测试结果
Cglib代理对象之前可以做的事情。。。。。
登录名:admin登录成功
欢迎玩家:雄霸天下
Cglib代理对象之后可以做的事情。。。。。
Cglib代理对象之前可以做的事情。。。。。
雄霸天下在打怪。。。
Cglib代理对象之后可以做的事情。。。。。
Cglib代理对象之前可以做的事情。。。。。
雄霸天下升了一级。。。
Cglib代理对象之后可以做的事情。。。。。
总结:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换