为什么要学习代理模式?因为这是SpringAOP的底层! 【SpringAOP和SpingMVC}】
代理模式的分类:
静态代理
动态代理
代理就像这里的中介,帮助你去做向房东租房,你不能直接解出房东,而房东和中介是因为租房而联系在一起,所以租房是接口
角色分析:
代码步骤:
接口
package com.hong;
//租房
public interface Rent {
public void rent();
}
真实角色
package com.hong;
public class Client {
public static void main(String[] args) {
//房东要租房子
Host host = new Host();
//代理,中介帮房东租房子,但是呢房东会加一些附属操作!
// host.rent();
Proxy proxy = new Proxy(host);
//你不用面对房东,直接找中介即可
proxy.rent();
}
}
代理角色
package com.hong;
public class Proxy implements Rent{
private Host host;
public Proxy(Host host) {
this.host = host;
}
public Proxy() {
}
@Override
public void rent() {
host.rent();
seeHost();
fare();
hetong();
}
//看房
public void seeHost(){
System.out.println("中介带你看房");
}
public void hetong(){
System.out.println("签合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户端访问代理角色
package com.hong;
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子");
}
}
代理模式的好处:
缺点:
用代理增加功能,不改动原有的代码,只改动代理类
package com.hong;
//真实对象
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("修改了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
}
package com.hong;
public class UserServiceProxy implements UserService{
private UserServiceImpl userservice;
public void setUserservice(UserServiceImpl userservice) {
this.userservice = userservice;
}
@Override
public void add() {
log("add");
userservice.add();
}
@Override
public void delete() {
log("delete");
userservice.delete();
}
@Override
public void update() {
}
@Override
public void query() {
}
public void log(String msg){
System.out.println("调用"+msg+"方法");
}
}
package com.hong;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
package com.hong;
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserservice(userService);
proxy.add();
}
}
需要了解两个类:proxy:代理,lnvocationHandler:调用处理程序
静态代理的好处:
实现代码
动态代理
package com.hong.demo02;
import com.hong.xxh.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object taget;
public void setTaget(Object taget) {
this.taget = taget;
}
//生成得到代理对象
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),taget.getClass().getInterfaces(),this);
}
//处理代理实例并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(taget, args);
return result;
}
}
接口
package com.hong.demo02;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
真实对象
package com.hong.demo02;
//真实对象
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("修改了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
}
客户端访问
package com.hong.demo02;
import com.hong.Proxy;
import com.hong.UserServiceImpl;
public class ClenClient {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTaget(userService); //设置要代理的对象
//动态生成代理
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}
我们将入口类定义为A
,我们最理想的情况是 A[O] -> O.f,那么我们将传进去的参数O
替换为B
即可。但是在实战的情况下这种情况是极少的。
回到实战情况,比如我们的入口类A
存在O.abc
这个方法,也就是 A[O] -> O.abc;而 O 呢,如果是一个动态代理类,O
的invoke
方法里存在.f
的方法,便可以漏洞利用了,我们还是展示一下。
A[O] -> O.abc O[O2] invoke -> O2.f // 此时将 B 去替换
O2 最后 ----> O[B] invoke -> B.f // 达到漏洞利用效果
就像readObject
在反序列化中自动调用,invoke
在动态代理的时候也自动调用,如果我们在invoke
插入恶意代码,就可进行攻击例如