Talk about static proxy and dynamic proxy

1. Static proxy

Before running, the bytecode file of the proxy class has been obtained through the logic code, and it can only proxy a single service object. If there are multiple service objects, each object has to create its own proxy class


/**
 * 代理接口
 * @author xnn
 * @date 2021-09-30 10:58
 */
public interface Subject {
    
    

    void doSomeThing(String thing);
}
/**
 * 真正执行任务的类
 */
public class RealSubject implements Subject {
    
    

    /**
     * 执行任务。
     * @param thing
     */
    @Override
    public void doSomeThing(String thing) {
    
    
        System.out.println("搞事情:"+ thing);
    }
}
/**
 * 代理类,实现了代理接口
 * @author xnn
 * @date 2021-09-30 11:02
 */
public class ProxySubject implements Subject{
    
    
    /**
     * 代理类持有一个委托类的对象引用
     */
    private Subject delegate;

    public ProxySubject(Subject delegate) {
    
    
        this.delegate = delegate;
    }

    /**
     * 将请求分派给委托类执行
     *
     * @param thing
     */
    @Override
    public void doSomeThing(String thing) {
    
    
        //将请求分派给委托类处理
        delegate.doSomeThing(thing);
    }

}
/**
 * 静态代理类工厂
 * @author xnn
 * @date 2021-09-30 11:02
 */
public class SubjectStaticFactory {
    
    

    //调用此工厂方法获得代理对象,其并不知道返回的是代理类对象还是委托类对象。
    public static Subject getInstance(){
    
    
        return new ProxySubject(new RealSubject());
    }

    public static void main(String[] args) {
    
    
        Subject proxy = SubjectStaticFactory.getInstance();
        proxy.doSomeThing("我要搞事情了!");
    }
}

Two, dynamic agent

Agency relationships are determined at runtime

The difference between JDK and CGLIB dynamic proxy

  • JDK dynamic proxies can only generate proxies for classes that implement interfaces, not for classes;
  • CGLIB loads the class file of the proxy object class, and processes it by modifying its bytecode to generate a subclass, mainly generating a subclass for the specified class and overriding the methods in it. Because it is inheritance, it is best not to declare this class or method as final

2.1, JDK agent

The proxy class implements the InvocationHandler interface, and all interface method calls to the proxy object will be forwarded to the InvocationHandler.invoke() method, in which we can add any logic. For methods inherited from Object, JDK Proxy will forward the three non-interface methods hashCode(), equals(), and toString() to InvocationHandler, and the remaining Object methods will not be forwarded.

public interface ISayHello {
    
    
    void sayHello(); 
}
public class SayHelloImpl implements ISayHello {
    
    
    @Override
    public void sayHello() {
    
    
        System.out.println("This is the JDK dynamic proxy");
    }
}

public class JdkProxy implements InvocationHandler {
    
    

    private Object target;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        System.out.println("=========="+method.getName()+"=============");
        System.out.println("------JDK动态代理开始-------");
        Object result = method.invoke(target, args);
        System.out.println("------JDK动态代理结束-------");

        return result;
    }
    /**
     * 获取代理对象
     **/
    private Object newProxyInstance(Object targetObject){
    
    
        // 目标对象赋值
        this.target = targetObject;
        // 返回代理对象
       	// loader,指定代理对象的类加载器;
		// interfaces,代理对象需要实现的接口,可以同时指定多个接口;
		// handler,方法调用的实际处理者,代理对象的方法调用都会转发到这里。
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public static void main(String[] args) {
    
    
        // 获取代理对象
        ISayHello sayHello = (ISayHello) (new JdkProxy().newProxyInstance(new SayHelloImpl()));
        sayHello.sayHello();
    }
}

//运行结果:
//==========sayHello=============
//------JDK动态代理开始-------
//This is the JDK dynamic proxy
//------JDK动态代理结束-------

2.2, CGLib dynamic proxy

Through CGLIB Enhancer, specify the target object to be proxied (target.getClass()), the object that actually handles the proxy logic (this), and finally get the proxy object by calling the create() method. All non-final method calls to this object will be Forward to the MethodInterceptor.intercept() method. In the intercept() method, we can add any logic, such as modifying method parameters, adding log functions, security check functions, etc. The function of the MethodInterceptor in CGLIG is very similar to that of the InvocationHandler in the JDK agent, both of which are transfer stations for method calls. For methods inherited from Object, CGLIB proxy will also perform proxy, such as hashCode(), equals(), toString(), etc., but getClass(), wait() and other methods will not, because it is a final method, CGLIB cannot acting.

2.2.1. Define entities

public class User {
    
    

    /**
     * user's name.
     */
    private String name;

    /**
     * user's age.
     */
    private int age;

    /**
     * init.
     *
     * @param name name
     * @param age  age
     */
    public User(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

2.2.2, the class being proxied

Enhance the method in the proxied class

public class UserServiceImpl {
    
    

    /**
     * find user list.
     *
     * @return user list
     */
    public List<User> findUserList() {
    
    
        return Collections.singletonList(new User("pdai", 18));
    }

    /**
     * add user
     */
    public void addUser() {
    
    
        // do something
    }

}

2.2.3, cglib proxy

Implement the MethodInterceptor interface and specify the proxy target class target

public class UserLogProxy implements MethodInterceptor {
    
    

    /**
     * 业务类对象,供代理方法中进行真正的业务方法调用
     */
    private Object target;

    public Object getUserLogProxy(Object target) {
    
    
        //给业务对象赋值
        this.target = target;
        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(this.target.getClass());
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        return enhancer.create();
    }

    // 实现回调方法
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    
    
        // log - before method
        System.out.println("[before] execute method: " + method.getName());

        // call method
        Object result = proxy.invokeSuper(obj, args);

        // log - after method
        System.out.println("[after] execute method: " + method.getName() + ", return value: " + result);
        return null;
    }
}

Call the proxy target and execute

public class ProxyDemo {
    
    

    /**
     * main interface.
     *
     * @param args args
     */
    public static void main(String[] args) {
    
    
        // proxy
        UserServiceImpl userService = (UserServiceImpl) new UserLogProxy().getUserLogProxy(new UserServiceImpl());

        // call methods
        userService.findUserList();
        userService.addUser();
    }
}

//运行结果:
//[before] execute method: findUserList
//[after] execute method: findUserList, return value: [User{name='pdai', age=18}]
//[before] execute method: addUser
//[after] execute method: addUser, return value: null

Guess you like

Origin blog.csdn.net/weixin_44153131/article/details/128990379