Proxy

静态代理我们知根知底,我们知道要对哪个接口、哪个实现类来创建代理类,
所以我们在编译前就直接实现与实现类相同的接口,
直接在实现的方法中调用实现类中的相应(同名)方法即可;

动态代理不同,我们不知道它什么时候创建,也不知道要创建针对哪个接口、
实现类的代理类(因为它是在运行时因需实时创建的)。

虽然二者创建时机不同,创建方式也不相同,但是原理是相同的
不同之处仅仅是:静态代理可以直接编码创建,
而动态代理是利用反射机制来抽象出代理类的创建过程。

静态代理

假设有一个接口C,A实现C接口的功能,B也去实现C接口,在B的实现 方法中直接调用A的实现

代码如下:

接口C

public interface UserService {
    public void login();
}

A实现C接口的功能

@Service("service")
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao dao;

    @Override
    public void login() {

        System.out.println("false");
    }
}

B直接调用A的实现

@Service
public class UserServiceProxyImpl implements UserService {

    private UserService service;

    public UserServiceProxyImpl() {
        service = new UserServiceImpl();
    }

    @Override
    public void login() {
        System.out.println("do something before login");
        service.login();
        System.out.println("do something after login");
    }
}

使用如下:

public class StaticProxyTest {
    public static void main(String[] args) {
        UserService service = new UserServiceProxyImpl();
        service.login();
    }
}

jdk动态代理

1 编写一个接口

public interface UserService {
    public void login();
}

2 自定义一个InvocationHandler 重写Invoke方法 , 这里通过反射的方式获取类的方法(method.invoke())

public class ServiceInvocationHandler implements InvocationHandler {
    UserService userService;

    public ServiceInvocationHandler(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("jdk do something before ");
        method.invoke(userService,objects);
        System.out.println("jdk do something after");
        return null;
    }
}

3 调用Proxy的静态方法 newProxyInstance 方法, 参数分别为类记载器,类接口数组new Class[],InvocationHandler

  UserService service = (UserService) Proxy.newProxyInstance(
                  ProxyTest.class.getClassLoader(),new Class[]{UserService.class}, new ServiceInvocationHandler(new UserServiceImpl()));

4 用新生成的代理实例调用某个方法实现功能

service.login();
  • 在 2中可以初始化原始的userService,然后在 3中初始化代理实例的时候传入被代理类

  • java动态代理,ProxyGenerator.generateProxyClass, 生成一个二进制数组byte[]的代理类, 。。。通过generateClassFile(),

  • 通过反编译的结果发现生成的代理类继承了Proxy,所以java动态代理只能实现接口

5 反编译过程

public class ProxyTest2 {
    public static void main(String[] args) throws Exception {
        byte[] bytes = ProxyGenerator.generateProxy();
        FileOutputStream fileOutputStream = new FileOutputStream("$Proxy1.class");
        fileOutputStream.write(bytes);
        fileOutputStream.flush();
        fileOutputStream.close();

    }
}

6 反编译生成类的代码

cglib代理

cglib是对一个小而快的字节码处理框架 ASM 的封装。
他的特点是继承于被代理类,这就要求被代理类不能被 final 修饰

Last updated