SpringAOP advanced (life example -> proxy mode -> source code analysis)

        After the foundation of the first two articles, finally came to the learning of Spring AOP knowledge

        Before talking about AOP, let’s talk about the design pattern used in it-the proxy design pattern

What is an agent? Why should there be an agent?

Small examples of life:

现在很多公寓式租房就是采用代理模式

角色:

房东、租房代理、房客

角色需求:

房东:需要房客入租客房,只想签合同收钱,但房源信息的宣传,打广告等额外的工作较为繁杂

房客:需要了解房源信息,以确保租房体验得到保证

矛盾:房东不想要宣传和打广告这些繁杂的工作,他只希望房客直接来跟他交钱签合同,然后入住就ok了,但是,如果没有宣传和广告这部分工作就会导致房客不能看到相应的房源信息,得不到保障,从而不敢或者不愿意去租房

解决问题者:租房代理

租房代理责任:代替房东,对房源信息进行宣传和做广告,包括一切帮助房客了解房源的工作



最后再来梳理一下每个角色的需求和责任:

房东:负责入住合同的签署和收取房费

代理:负责对房源信息进行宣传和帮助房客了解房源,大型代理还可以帮助房东管理房客入住后的所有事情(合同收钱除外)

房客:通过房源信息广告和实地了解后跟房东签署入住合同

这样上面的矛盾就得到了解决,并且房东和房客都不会有太多的顾虑和多余的繁杂事儿

analysis:

According to the above living examples, the rental agency needs to call the landlord’s method of signing the contract. Based on this requirement, our proxy object and the proxy object (target object) must implement the same interface to ensure that the proxy object can have the proxy object (target Object) method, call the contract signing method of the proxy object (target object) in the contract signing method of the proxy object

From the above small examples of life, we can see the importance of agency and the meaning of its existence—————— Solve the contradiction between landlord and tenant due to housing information

It may be a bit confusing to understand the above words, now we will implement it in the Java code to see

JEE development is mainly divided into three layers: Controller——>Service——>Dao

The Service layer is the most important layer, because our business code is written in this layer, let’s take a look at what code the Service layer contains

Service layer  = core function (business code ) + additional function ( additional function )
 
1. Core function
        Business computing
        DAO call
2. Extra features
        1. Not a business
       2. Available
       3. The amount of code is very small
 
      What are the additional functions: transaction, log, performance ...
 

At this time, there is a problem. Can we directly write the additional function code in the Service layer? Why does it need to be brought up as a separate piece?

analysis:

Service caller: I hope that additional functions are written in the Service layer————————Guest

Software designer: I hope that the Service layer only writes business code, and does not require additional functional code to confuse the business————————The landlord

So there will be differences! ————This is similar to the conflict between the landlord and the tenant due to the listing information

Solution: Use proxy mode!

Agency model

代理(Proxy)是一种设计模式,提供了对目标对象的另一种(非直接)访问方式

访问者通过代理对象来间接的访问目标对象

优点:实现目标对象业务功能的同时,能增加额外的功能和操作,即扩展目标对象

日常开发思想:不要随意去修改别人已经写好的代码或者方法,如需修改,则可以通过代理的方式来扩展该方法

代理模式的关键点:代理对象和目标对象,代理对象是对目标对象的扩展,并会调用目标对象

The concept of proxy mode: through proxy classes, to increase the additional functions of the original class (target)

Target class, original class: refers to the business class ( core function --> business operation DAO call )

Target method, original method: method in the target class or original class

Additional functions, additional functions: log, transaction, performance

Proxy class = target class (original class) + additional functions + implement the same interface as the original class (target class)

#接口
public interface UserService{

        A(); //A方法
        B(); //B方法

}

#原始类(目标类)————房东

public class UserServiceImpl implements UserService{

        A(){} //A方法
        B(){} //B方法

}

#代理类(额外功能)————————租房代理

public class UserServiceProxy implements UserService{

        A(){} //A方法
        B(){} //B方法

}


Well, at this point, the agent should be explained clearly from life to code, so now we have to understand the agent design pattern in depth!

Agent model classification

Static proxy: For each primitive class, manually write a proxy class (.java .class)

Dynamic proxy: It is not necessary to manually write proxy classes for each proxy class. The third-party dynamic bytecode technology provides a .class bytecode template for the proxy class.

扩展:

正常情况下我们创建一个类————在这里指的是代理类

1.从本地或网络加载.calss文件
2.根据.class文件在方法区中创建一个class字节码模板用于提供该类的模板信息(元信息)
3.根据class字节码模板在堆空间中创建一个java.lang.class对象
4.当我们需要实例对象的时候再通过class对象在堆空间中创建相应的实例对象


在这些步骤中,最重要的是我们必须要拿到.class字节码模板,
但是在动态代理中这个字节码模板是由第三方动态字节码技术来提供的——————具体是哪些第三方技术,请往下看!!!!!

Understand the theory, then explain, code! ! ! !

Static proxy:

步骤:
1.提供业务接口
2.编写业务类(目标类)及方法
3.编写代理类,要求和目标类实现相同的接口,并调用目标类的方法
4.调用代理类的方法

1. Provide business interface

public interface UserService {

    public void register();
}

2. Write business class (target class) and methods

public class UserServiceImpl  implements UserService {
    @Override
    public void register() {
        System.out.println("我是业务代码!!!");
    }
}

3. Write the proxy class, require the same interface as the target class, and call the method of the target class

public class UserServiceProxy implements UserService {

    private final UserServiceImpl userService = new UserServiceImpl();
    @Override
    public void register() {
        System.out.println("我是额外功能!!!");
        userService.register();
    }
}

4. Call the method of the proxy class

5. Results

Well, the theory and coding have been realized, the next step is to analyze

analysis:

Static proxy

     Advantages: The business class is enhanced without modifying the business class (target class) code

     Disadvantages: Because the proxy class needs to implement the same interface as the target class, if there are more business classes, there will be many proxy classes. At the same time, once the interface adds methods, the target object and the proxy object must be maintained

So how to solve the problem caused by static proxy? !

At this time, Spring's dynamic agent drove its Maserati Benz!

 

Let's first take a look at how to use Spring's dynamic proxy development:

Dynamic proxy:

Spring动态代理编程步骤:
1.引入依赖
2.创建接口和目标类(业务类)
3.编写额外功能类
4.定义切入点
5.组装切面(组装步骤3和步骤4)
6.调用测试
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.1.14.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.8.8</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.3</version>
</dependency>
#准备接口和目标类(业务类)

public interface OrderService {

    void productOder();

    Boolean consumOrder();

}

public class OrderServiceImpl implements OrderService {
    @Override
    public void productOder() {
        System.out.println("下单");
    }

    @Override
    public Boolean consumOrder() {
        System.out.println("消费订单");
        return true;
    }
}

#准备额外功能类

public class OrderExtra1 implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("我是订单需要的额外功能!!!");
    }
}

#在xml中将目标类和额外功能类交给Spring去管理

<bean id="orderSevice" class="com.xiaozhao.spring.service.impl.OrderServiceImpl"/>

<bean id="orderExtra" class="com.xiaozhao.spring.service.extra.orderExtra1"/>

#设置切入点和组装切面

<aop:config>
   <aop:pointcut id="extra" expression="execution(* *(..))"/> //切入点
   <aop:advisor advice-ref="orderExtra" pointcut-ref="extra"/> //组装
</aop:config>
测试:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");

OrderService orderSevice = (OrderService) ctx.getBean("orderSevice");
orderSevice.productOder();
orderSevice.consumOrder();

analysis:

public class orderExtra1 implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("我是订单需要的额外功能!!!");
    }
}

From the results, we can see the role of the MethodBeforeAdvice interface:

Parameter analysis:

Method method: target method (method in the target class)

Object[] objects: parameters of the target method

Object o: target class (target object)

Write the extra function in the before method of the MethodBeforeAdvice interface implementation class, and operate before the original method is executed, and then enhance the target method, but this method has a drawback that we can only add the corresponding extra function before the original method, if we Want to add corresponding additional functions before and after the original method? For example, the transaction needs to open the transaction before the original method, and close the transaction after the original method, in order to ensure that our operations are atomic. Under such requirements, the interface It can't meet our needs!

We have considered this drawback, obviously the designers of Spring will also think of it, so Spring prepares another interface for us to help us solve this problem

MethodInterceptor (method interceptor):

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
    Object invoke(MethodInvocation var1) throws Throwable;
}

Its function is the same as the MethodBeforeAdvice interface, but it also adds extra functions to the original method, but the difference is that MethodInterceptor can add extra functions before and after the original method. Specifically how it is implemented, we will continue to code!

#在这里重复的步骤我就不在贴出来了,就是简单的将上面的MethodBeforeAdvice实现添加额外功能中额外功能的代码替换成一下代码:


/**
 * @author : Carson-Zhao
 * @date : 2020/9/16 23:02
 */
public class OrderExtra2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("原始方法之前!");//原始方法前

        Object ret = methodInvocation.proceed();//原始方法回调

        System.out.println("原始方法之后!");//原始方法后

        return ret;
    }
}


#在xml中修改组装的额外功能

<bean id="orderExtra" class="com.xiaozhao.spring.service.extra.OrderExtra2"/>


#最后调用一下这两个方法

ClassPathXmlApplicationContext ctx =
                new ClassPathXmlApplicationContext("/applicationContext.xml");

        OrderService orderSevice = (OrderService) ctx.getBean("orderSevice");

        orderSevice.productOder();

        System.out.println("我是分割线================");

        orderSevice.consumOrder();


operation result:

analysis:

public class OrderExtra2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("原始方法之前!");//原始方法前

        Object ret = methodInvocation.proceed();//原始方法回调

        System.out.println("原始方法之后!");//原始方法后

        return ret;
    }
}

There is a method invoke in the MethodInterceptor interface, the method parameter is methodInvocation, the proceed method using this parameter can call back the original method (callback means to execute the original method), and return the return value of the original method ( note! If the original method If there is no return value, then the ret here is null ), we can add our additional function code (transaction, log, performance monitoring... etc.) before or after this line of code and before and after

Expansion:

When using the MethodInterceptor interface to add additional functions, if the original method throws an exception, additional functions can be added in the catch block (scene: exception log). The specific implementation is a simple try/catch block, here is Don’t demonstrate!

supplement:

Although the MethodInterceptor interface is easier to use and more common, it is not perfect. One of its drawbacks is that it is not a drawback, that is, after the method callback process, the return value of the original method can be changed, thereby changing the return value of the original method

/**
 * @author : Carson-Zhao
 * @date : 2020/9/16 23:02
 */
public class OrderExtra2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        System.out.println("原始方法之前!");
        Object ret = methodInvocation.proceed();
        System.out.println("原始方法之后!");

        return true;//不将原始方法的返回值进行返回,就可以改变原始方法的返回值
        
    }
}

to sum up:

        In contrast, the two interfaces MethodBeforeAdvice and MethodInterceptor are commonly used in actual development. The former is rarely used, so here the former is mainly for understanding, and the latter is to learn to use it! But the invoke method in the MethodInterceptor interface can change the return value of the original method.

Well, so far, we have only talked about the basic principles of dynamic proxy in a more general way. In order to understand Spring Dynamic Proxy (AOP) more deeply, let’s sublime it a bit and take a look at the underlying implementation principle.

From the above example, we know that Spring dynamic proxy no longer needs us to write proxy classes manually, but only need to focus on business processing of business classes. Compared with static proxy, it is obviously a great advantage. Then think about whether there is a proxy in this process. class? If so, how does AOP create proxy classes? How does Spring process proxy objects?

How to create the proxy class:

JDK dynamic proxy:

Spring中动态代理类的相关细节分析:

动态代理类特点:

1.访问修饰符为public,final和非抽象类型的

2.继承了java.lang.reflect.Proxy类,实现了getProxyClass()和newProxyInstance方法

3.有一个public类型的构造方法,该方法有一个InvocationHandler类型的参数

4.当程序调用动态代理实例的方法时,会调用与之关联的InvocationHandler对象的invoke方法

扩展:

1、Proxy类的isProxyClass静态方法可以用来判断指定的类是否为动态代理类

From the above characteristics, we can see that the dynamic proxy class is closely related to java.lang.reflect.Proxy, so let's take a look at the source code of Proxy to pretend to be analyzed.


JDK实现的动态代理:

Object ProxyClass = Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);

分析:

ProxyClass:动态代理类

classLoader:类加载器

interfaces: 原始类实现的接口

invocationHandler:额外功能



为了减省太多干扰信息,我就截取相关重要的部分源码进行强行分析

public class Proxy implements java.io.Serializable {

    //生成代理类实例
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        //验证传入的InvocationHandler是否为空
        Objects.requireNonNull(h);
        
        //克隆代理类实现的接口
        final Class<?>[] intfs = interfaces.clone();
        //获得安全管理器
        final SecurityManager sm = System.getSecurityManager();
        //检查创建代理类所需的权限
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         * 查找或者生成特定的代理类(如果缓存中存在,则直接获取)
         */
        // 查找缓存或者生成一个特定的代理类对象(缓存中没有对应的代理对象时,就会去生成新的代理对象)—————————关键!!!!
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            //权限校验
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //获取参数类型是InvocationHandler.class的代理类构造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            //如果代理类是不可访问的, 就使用特权将它的构造器设置为可访问
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //传入InvocationHandler实例去构造一个代理类的实例,所有代理类都继承自Proxy,而Proxy构造方法需要InvocationHandler实例作为参数
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        //如果缓存中有实现给定接口的代理类存在,就返回缓存中的副本;否则,将通过ProxyClassFactory创建代理类
        return proxyClassCache.get(loader, interfaces);
    }

    //当缓存中不存在副本时,则由ProxyClassFactory生成
    /**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
    {
        // prefix for all proxy class names 做一个标识所有代理类名称前缀
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names 用原子类来生成代理类的序号, 保证序号唯一
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                //intf是否可以由指定的类加载进行加载
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.//判断intf是不是接口
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate//验证intf在数组中是不是重复的
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }
            //生成代理类的包名
            String proxyPkg = null;     // package to define proxy class in
            //代理类的访问标志, 默认是public和final
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             * //验证所有非公共代理接口都在同一个包中
             */

            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                //如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同
                if (!Modifier.isPublic(flags)) {
                    //生成代理类的访问标志设置改为final
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            //代理类如果实现不同包接口, 并且接口都不是public的, 那么就会在这里报错
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package 如果不存在非公正代理包则使用com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * Choose a name for the proxy class to generate.
             * 生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg(包名) + proxyClassNamePrefix(类名前缀) + num(序号);

            /*
             * Generate the specified proxy class.
             * 生成代理代理的字节码!!!!——————————————————————动态代理的关键
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);//获取代理字节码文件
            try {
                //根据二进制文件生成相应的Class实例
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

    //根据指引我们来到generateProxyClass这个方法
    public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {        
        ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);//构造ProxyGenerator对象
        final byte[] var4 = var3.generateClassFile();——————————————获取字节码!!!!!——————关键方法
        //如果saveGeneratedFiles为true,则表示需要保存生成的字节码文件,将字节码文件写入磁盘
        if (saveGeneratedFiles) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int var1 = var0.lastIndexOf(46);
                        Path var2;
                        if (var1 > 0) {
                            Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));//路径
                            Files.createDirectories(var3);
                            var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
                        } else {
                            var2 = Paths.get(var0 + ".class");
                        }

                        Files.write(var2, var4, new OpenOption[0]);//写入磁盘
                        return null;
                    } catch (IOException var4x) {
                        throw new InternalError("I/O exception saving generated file: " + var4x);
                    }
                }
            });
        }
        //将字节码数组返回
        return var4;
    }

    //继续跟随以上方法,追溯ProxyGenerator.generateClassFile方法

    private byte[] generateClassFile() {
        //第一步、将所有方法组装成ProxyMethod对象,并为代理类生成toString, hashCode, equals等代理方法
        this.addProxyMethod(hashCodeMethod, Object.class);
        this.addProxyMethod(equalsMethod, Object.class);
        this.addProxyMethod(toStringMethod, Object.class);
        Class[] var1 = this.interfaces;
        int var2 = var1.length;

        int var3;
        Class var4;
        for(var3 = 0; var3 < var2; ++var3) {
            //遍历每一个接口的每一个方法, 并生成ProxyMethod对象
            var4 = var1[var3];
            Method[] var5 = var4.getMethods();
            int var6 = var5.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Method var8 = var5[var7];
                this.addProxyMethod(var8, var4);
            }
        }

        Iterator var11 = this.proxyMethods.values().iterator();

        List var12;
        while(var11.hasNext()) {
            var12 = (List)var11.next();
            checkReturnTypes(var12);
        }
        //第二步、组装要生成的class文件的所有字段信息和方法信息
        Iterator var15;
        try {
            添加构造器
            this.methods.add(this.generateConstructor());
            var11 = this.proxyMethods.values().iterator();
            //遍历缓存中的代理方法
            while(var11.hasNext()) {
                var12 = (List)var11.next();
                var15 = var12.iterator();

                while(var15.hasNext()) {
                    ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
                    //添加代理类的静态字段
                    this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
                    //添加代理类的代理方法
                    this.methods.add(var16.generateMethod());
                }
            }
            //添加代理类的静态字段初始化方法
            this.methods.add(this.generateStaticInitializer());
        } catch (IOException var10) {
            throw new InternalError("unexpected I/O Exception", var10);
        }

        if (this.methods.size() > 65535) {
            throw new IllegalArgumentException("method limit exceeded");
        } else if (this.fields.size() > 65535) {
            throw new IllegalArgumentException("field limit exceeded");
        } else {
            //第三步、写入最终class文件
              //验证常量池中存在代理类的全限定名
              this.cp.getClass(dotToSlash(this.className));
              //验证常量池中存在代理类父类的全限定名
              this.cp.getClass("java/lang/reflect/Proxy");
              var1 = this.interfaces;
              var2 = var1.length;
  
              //验证常量池存在代理类接口的全限定名
              for(var3 = 0; var3 < var2; ++var3) {
                  var4 = var1[var3];
                  this.cp.getClass(dotToSlash(var4.getName()));
              }
  
              //开始写入文件了,设置常量池只读
              this.cp.setReadOnly();
              ByteArrayOutputStream var13 = new ByteArrayOutputStream();
              DataOutputStream var14 = new DataOutputStream(var13);
  
              try {
                  //1.写入魔数
                  var14.writeInt(-889275714);
                  //2.写入次版本号
                  var14.writeShort(0);
                  //3.写入主版本号
                  var14.writeShort(49);
                  //4.写入常量池
                  this.cp.write(var14);
                  //5.写入访问修饰符
                  var14.writeShort(this.accessFlags);
                  //6.写入类索引
                  var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
                  //7.写入父类索引, 生成的代理类都继承自Proxy
                  var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
                  //8.写入接口计数值
                  var14.writeShort(this.interfaces.length);
                 
                 Class[] var17 = this.interfaces;
                int var18 = var17.length;
 
                 //9.写入接口集合
                 for(int var19 = 0; var19 < var18; ++var19) {
                     Class var22 = var17[var19];
                     var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
                 }
                 //10.写入字段计数值
                 var14.writeShort(this.fields.size());
                 var15 = this.fields.iterator();
                 //11.写入字段集合 
                 while(var15.hasNext()) {
                     ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
                     var20.write(var14);
                 }
                 //12.写入方法计数值
                 var14.writeShort(this.methods.size());
                 var15 = this.methods.iterator();
                 //13.写入方法集合
                 while(var15.hasNext()) {
                     ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
                     var21.write(var14);
                 }
                  //14.写入属性计数值, 代理类class文件没有属性所以为0
                 var14.writeShort(0);
                 //转换成二进制数组输出
                 return var13.toByteArray();
             } catch (IOException var9) {
                 throw new InternalError("unexpected I/O Exception", var9);
             }
         }
    }
}

The above code may be more confusing and
    simple to summarize:

思想:通过类加载器获取类字节码,通过类实现的接口反射获得该类的属性和方法,并生成新的字节码文件

参数分析:

参数一:

类加载器————————创建实例对象所需的类加载器,可借用(前文有提及创建实例对象需要类加载器)

参数二:

原始类实现的接口———————JDK动态代理最重要的就是保证代理类和原始类实现相同的结果,代理类的代理方法中调用原始类的原始方法,所以我们这里需要传一个原始类实现的接口作为参数

参数三:

额外功能——————需要实现InvocationHandler接口的invoke方法

CGLIB dynamic agent:

CGLIB动态代理原理和JDK动态代理原理有些类似

区别是:

 在Object ProxyClass =Proxy.newProxyInstance(classLoader,SuperClass,invocationHandler)
 这里的时候第二个参数不再是是原始类实现的接口,而是直接传原始类

    原因:代理类不再需要和原始类实现同一个接口去获取方法,而是直接继承原始类来获取原始方法


在这里Spring给我们提供了一个新的对象Enhancer,通过这个对象来set所需的三个参数(类加载器,原始类,额外功能)


例子:


/**
 * @author : Carson-Zhao
 * @date : 2020/9/11 23:44
 */
public class demo {

    public static void main(String[] args) {

        OrderServiceImpl orderService = new OrderServiceImpl();

        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(demo.class.getClassLoader());
        enhancer.setSuperclass(orderService.getClass());

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

                System.out.println("额外功能1");
                Object ret = method.invoke(orderService, args);
                System.out.println("额外功能2");
                return ret;
            }
        };
        enhancer.setCallback(interceptor);

        OrderService orderServiceProxy = (OrderService) enhancer.create();
        orderServiceProxy.productOder();
        orderServiceProxy.consumOrder();

    }
}

The results of the above code:

to sum up:

There are two ways for AOP to create dynamic agents:

1. JDK dynamic proxy

2. CGLIB dynamic agent

The difference between the two:

JDK implements the original method of calling the original class by implementing the same interface between the proxy class and the original class. CGLIB uses the proxy class to implement the original class to call the original method in the original class.

JDK————Implement the same interface implemented by the original class

CGLIB————Inherit the original class

 

nagging:

At this point, the AOP is almost explained clearly. There are basics and a little bit of depth. It is considered to be consolidated after sorting out the knowledge points. I hope that the fat friends who read the article will encourage together

plan:

The next plan is to learn the secondary packaging of RedisTemplate, which is mainly used for our daily development

At last:

Everyone who is great has a hard time, but as long as you persist like SB, you will be great!

Guess you like

Origin blog.csdn.net/weixin_43562937/article/details/108433077