谈谈静态代理和动态代理

一、静态代理

在运行前,已经通过逻辑代码有了代理类的字节码文件,只能代理单一的服务对象,有多个服务对象的话每个对象都得创建自己的代理类


/**
 * 代理接口
 * @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("我要搞事情了!");
    }
}

二、动态代理

代理关系是在运行时期确定的

JDK和CGLIB动态代理的区别

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类;
  • CGLIB对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final

2.1、JDK代理

代理类实现InvocationHandler接口,对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑。对于从Object中继承的方法,JDK Proxy会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发。

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动态代理

通过CGLIB的Enhancer来指定要代理的目标对象(target.getClass())、实际处理代理逻辑的对象(this),最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等。CGLIG中MethodInterceptor的作用跟JDK代理中的InvocationHandler很类似,都是方法调用的中转站。对于从Object中继承的方法,CGLIB代理也会进行代理,如hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是final方法,CGLIB无法代理。

2.2.1、定义实体

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、被代理的类

对被代理的类中的方法进行增强

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代理

实现MethodInterceptor接口,并指定代理目标类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;
    }
}

调用代理目标并执行

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

猜你喜欢

转载自blog.csdn.net/weixin_44153131/article/details/128990379