代理模式
23中(Gof)中代理模式中的一种,AOP本身就是基于动态代理实现的,所以掌握了代理模式对AOP的学习很有帮助,所以先讲下代理模式
概念:
真实对象:要进行功能扩展的对象
真实方法:要扩展功能的方法
代理对象:功能扩展后的对象
代理方法:功能扩展后的方法
流程:
没有扩展前的调用流程
调用--->真实对象--->真实方法
扩展后的调用方式:
调用--->代理对象--->代理方法--->真实对象--->真实方法
作用:
在不修改真是方法的代码的基础上完成功能的扩展
注意:
在代理设计模式中,虽然可以实现在不修改真实方法的源码
基础上完成功能的扩展,但是我需要改变调用方式由直接调用
真实对象的真实方法--->调用代理对象的代理方法。为了方便我们
进行替换,一般我们会将代理方法和真实方法设计的方法名和形参和
返回值一样,为了规范代码的编写,由如下两种实现:
①真实对象和代理对象实现相同的接口
②代理对象继承真实对象
静态代理模式
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。
通常情况下, 静态代理中的代理类和目标类会实现同一接口或是派生自相同的父类。
概念: 代理对象和代理方法由程序员自己编写的方式称为静态代理
流程:
①创建代理对象,实现和真是对象相同的接口或者继承真是对象
②在代理对象中重写真实方法,称为代理方法
③分别创建对象,声明扩展代码
④在代理方法中调用扩展代码,调用真实方法
⑤将源码中调用真实对象的代码修改为调用代理对象
特点:
代理对象和代理方法由程序员自己编写
缺点:
程序员自己编写代理对象和代理方法,开发效率低
创建接口和实现类
//定义公共接口
public interface UserService {
String doSome(String info);
}
// 静态代理模式的实现类
public class UserServiceImpl implements UserService {
@Override
public String doSome(String info) {
System.out.println("目标对象方法执行了"+info);
return "hello";
}
}
创建静态代理类
/**
* 代理类
* 1.实现和目标对象相同的接口
* 2.要具有目标对象的引用
*/
public class UserProxy implements UserService{
//目标对象
private UserService target;
public UserProxy(UserService target){
super();
this.target = target;
}
@Override
public String doSome(String info) {
//执行目标对象的方法
String msg = target.doSome(info);
return msg.toUpperCase();
}
}
测试
动态代理模式
概念:
代理对象和代理方法是动态生成的方式称为动态代理。
作用:
实现代理对象和代理方法的动态生成的同时,又可以让我们自己灵活的编写扩展代码。
代理类在程序运行时创建的代理方式被成为 动态代理。
也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。
代理类型 | 使用场景 |
---|---|
JDK动态代理 | 如果目标对象实现了接口,采用JDK动态代理 |
cglib动态代理 | 如果目标对象没有实现接口,必须采用CGLIB动态代理 |
JDK动态代理:基于接口
流程:
1.创建一个实现了InvocationHandler接口的普通java类,并重写invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
参数:
Object proxy:代理对象
Method method:接口类型的切点方法
Object[] args:代理方法接受的实参的数组。
返回值:
一般直接返回真实方法的返回值。
2.使用Proxy调用其newProxyIntance方法完成代理对象和代理方法的动态生成
Object obj=Proxy.newProxyIntance(ClassLoader class,Class<?>[],InvocationHandler in);
参数:
ClassLoader class:类加载对象,用来加载类文件,主要是夹在接口类文件
动态生成代理对象
Class<?>[]:接受要动态生成的代理对象需要实现的接口的类对象数组
InvocationHandler in:接受InvocationHandler 的实例化对象。
动态生成的代理方法会调用InvocationHandler接接口的
invoke方法,完成功能拓展。
返回值:
Object类型的代理对象,可以使用接口直接强制转换。
3.调用动态生成的代理对象的代理方法完成业务操作。
缺点:
基于反射动态实现效率比较低
代理对象和真实对象是基于接口关联的,需要程序员编写接口。
声明接口与实现
public interface UserService {
String doSome(String info);
}
public class UserServiceImpl implements UserService {
@Override
public String doSome(String info) {
System.out.println("目标对象方法执行了"+info);
return "hello";
}
JDK代理实现
public class Start {
public static void main(String[] args) {
//获取目标对象
UserService target = new UserServiceImpl();
//获取动态代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //实现类的类加载器
target.getClass().getInterfaces(), //目标对象实现的所有的接口
new InvocationHandler() { //InvocationHandler 实现类 具体的代理对象的处理对象
/**
* 代理对象需要执行的方法
* 比如 调用target中的doSome(),fun1()
* proxy 代理对象
* method 目标方法对象
* args 目标方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//目标方法的执行
Object msg = method.invoke(target, args);
if(msg != null && msg instanceof String){
return ((String)msg).toUpperCase();
}
return null;
}
});
System.out.println(proxy.doSome("111"));
}
}
CGLIB动态代理:基于继承
注意:
Cglib是基于继承的,底层是基于字节码文件反向动态生成代理对象的
是第三方提供的一种方式。需要导入相关jar包。
流程:
1.导入cglib相关jar包
asm-3.3.1.jar
cglib-2.2.2.jar
javassist-3.17.1-GA.jar
3.获取cglib的对象,用来动态生成代理对象
Enhancer en=new Enhancer();
3.设计代理对象需要继承的真实对象
en.setSuperclass(Boss.class);
参数为:真实对象的类对象
4.设置代理对象的回调对象
en.setCallback(new MyCglib());
参数为:实现了MethodInterceptor接口的类的实例化对象
5.生成代理对象
Boss b2=(Boss) en.create();
6.创建一个实现了MethodInterceptor接口的Java类型,并复写intercept方法
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3)
参数:
object arg0:代理对象
Method arg1:真实方法对象
Object[] arg2:代理方法接受的实现的数组
MethodProxy arg3:代理方法对象
返回值:
一般返回真实方法的返回值
缺点:
导入jar包
导入cglib-nodep-3.1.jar包
创建目标类
public class UserServiceImpl implements UserService {
@Override
public String doSome(String info) {
System.out.println("目标对象方法执行了"+info);
return "hello";
}
@Override
public void fun1() {
System.out.println("fun1方法执行了");
}
}
创建cglib工厂
public class CglibProxy implements MethodInterceptor{
private UserServiceImpl target;
public CglibProxy(UserServiceImpl target) {
super();
this.target = target;
}
//给外界提供的获取代理对象的方法
public UserServiceImpl getProxyObject(){
//1.获取个Enhancer增强器
Enhancer enhancer = new Enhancer();
//2.设置代理类的父类
enhancer.setSuperclass(UserServiceImpl.class);
//3.设置回调对象
enhancer.setCallback(this);
//4.创建代理对象并且返回
return (UserServiceImpl)enhancer.create();
}
//调用代理对象中的方法时 执行的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("目标对象执行前...");
//目标方法的执行
Object msg = method.invoke(target, args);
System.out.println("目标对象执行后...");
if(msg != null && msg instanceof String){
return ((String)msg).toUpperCase();
}
return null;
}
}
测试