代理设计模式
什么是代理
增强一个对象的功能
java实现代理
静态代理
继承
代理对象继承目标对象,重写需要增强的方法;
缺点:会代理类过多,非常复杂
public interface UserService {
void test1();
String test2(String str);
}
public class UserServiceImpl implements UserService {
@Override
public void test1() {
System.out.println("UserServiceImpl---test1");
}
@Override
public String test2(String str) {
System.out.println("UserServiceImpl---test2");
return str;
}
}
public class UserServiceLog extends UserServiceImpl {
@Override
public void test1() {
System.out.println("log---test1");
super.test1();
}
@Override
public String test2(String str) {
System.out.println("log---test2");
return super.test2(str);
}
}
public class UserServiceLogAndCheck extends UserServiceLog {
@Override
public void test1() {
System.out.println("check---test1");
super.test1();
}
@Override
public String test2(String str) {
System.out.println("check---test2");
return super.test2(str);
}
}
public class TestExtendsProxy {
public static void main(String[] args) {
UserService userService = new UserServiceLog();
userService.test1();//1
System.out.println(userService.test2("hello"));//2
UserService userService2 = new UserServiceLogAndCheck();
userService2.test1();//3
System.out.println(userService2.test2("world"));//4
}
}
他们的单独执行结果分别为
1:
log---test1
UserServiceImpl---test1
2:
log---test2
UserServiceImpl---test2
hello
3:
check---test1
log---test1
UserServiceImpl---test1
4:
check---test2
log---test2
UserServiceImpl---test2
world
显然,我们每写一个代理类,他的代理方法的执行顺序就已经固定了
比如,在现有的代码中,我们想只进行check代理,无法实现,必须再新建一个类,继承UserServiceImpl,对他进行代理
会产生非常多的类
聚合
目标对象和代理对象实现同一个接口,代理对象当中要包含目标对象。
缺点:也会产生类爆炸,只不过比继承少一点点
public interface UserService {
void test1();
String test2(String str);
}
public class UserServiceImpl implements UserService {
@Override
public void test1() {
System.out.println("UserServiceImpl---test1");
}
@Override
public String test2(String str) {
System.out.println("UserServiceImpl---test2");
return str;
}
}
public class UserServiceLog implements UserService {
private UserService userService;
public UserServiceLog(UserService userService) {
this.userService = userService;
}
@Override
public void test1() {
System.out.println("log--------test1");
userService.test1();
}
@Override
public String test2(String str) {
System.out.println("log--------test2");
return userService.test2(str);
}
}
public class UserServiceCheck implements UserService {
private UserService userService;
public UserServiceCheck(UserService userService) {
this.userService = userService;
}
@Override
public void test1() {
System.out.println("check---test1");
userService.test1();
}
@Override
public String test2(String str) {
System.out.println("check---test2");
return userService.test2(str);
}
}
public class TestAggregationProxy {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserService userServiceLog = new UserServiceLog(userService);
userServiceLog.test1();//1
System.out.println(userServiceLog.test2("hello"));//2
UserServiceCheck userServiceCheck = new UserServiceCheck(userServiceLog);
userServiceCheck.test1();//3
System.out.println(userServiceCheck.test2("world"));//4
}
}
他们的单独执行结果分别为
1:
log--------test1
UserServiceImpl---test1
2:
log--------test2
UserServiceImpl---test2
hello
3:
check---test1
log--------test1
UserServiceImpl---test1
4:
check---test2
log--------test2
UserServiceImpl---test2
world
显然,聚合相对于通过继承实现的静态代理,会灵活一点
比如,现有log和check两个代理类,我们可以实现只log代理,只check代理,先log再check,先check再log
当然也会产生很多类
动态代理
jdk动态代理
public interface UserService {
void test1();
String test2(String str);
}
public class UserServiceImpl implements UserService {
@Override
public void test1() {
System.out.println("UserServiceImpl---test1");
}
@Override
public String test2(String str) {
System.out.println("UserServiceImpl---test2");
return str;
}
}
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start-----" + method.getName());
if (null != args) {
args[0] = "被改的入参";
}
Object invoke = method.invoke(target, args);
System.out.println("end----" + method.getName());
return invoke;
}
public Object getProxy() {
return Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(), target.getClass().getInterfaces(), this);
}
}
public class TestDynamicProxy {
public static void main(String[] args) {
// 开启保存class文件,可以生成com.sun.proxy.$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
UserService userService = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService);
UserService proxy = (UserService) myInvocationHandler.getProxy();
proxy.test1();//1
System.out.println(proxy.test2("hello"));//2
}
}
他们的单独执行结果分别为
1:
start-----test1
UserServiceImpl---test1
end----test1
2:
start-----test2
UserServiceImpl---test2
end----test2
被改的入参
cglib
public class UserServiceImpl{
public void test1() {
System.out.println("UserServiceImpl---test1");
}
public String test2(String str) {
System.out.println("UserServiceImpl---test2");
return str;
}
}
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("start----");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("end----");
return invoke;
}
}
public class TestCglibProxy {
public static void main(String[] args) {
// 设置生成的class文件保存路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/ex-zhuchen001/Desktop");
CglibProxy cglibProxy = new CglibProxy();
UserServiceImpl proxy = (UserServiceImpl) cglibProxy.getProxy(UserServiceImpl.class);
proxy.test1();
}
}
执行结果为:
start----
UserServiceImpl---test1
end----
代理class文件的生成
在main方法中先执行如下代码
// jdk动态代理
// 开启保存class文件,可以生成com.sun.proxy.$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
// cglib动态代理
// 设置生成的class文件保存路径
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/my/Downloads");
jdk动态代理和cglib的异同
jdk动态代理是动态的生成一个java类,实现目标类所实现的接口,并且在其中调用目标类中的方法,所以必须有接口的类才能被代理.并且代理类和目标类都是实现同一个接口,他们并不能相互转换.
cglib实际上是通过继承目标类来生成代理类,所以无论是否有接口,都可以通过cglib来实现动态代理.由于代理类的父类是目标对象,所以代理类是可以赋值给目标对象的,自然如果目标对象有接口,代理对象也是可以赋值给接口的.
CGLIB 动态代理中生成的代理类的字节码相比 JDK 来说更加复杂。
JDK 使用反射机制调用目标类的方法,CGLIB 则使用类似索引的方式直接调用目标类方法,所以 JDK 动态代理生成代理类的速度相比 CGLIB 要快一些,但是运行速度比 CGLIB 低一些,并且 JDK 代理只能对有接口的目标对象进行代理。