[Tutorial] Detailed Spring AOP realization of the principle of (dynamic proxies)

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/sinat_27933301/article/details/94198281

I. Introduction

  AOP is Aspect-Oriented Programming, i.e. Oriented Programming.
  It is a new modular mechanism, used to describe dispersion crosscutting concerns in the object / class or function. Separation of concerns makes the code to solve a specific problem areas independent from the business logic, business logic code no longer contains the calling code for a specific problem areas, business logic with a specific problem areas to encapsulate by section, to maintain, so the original changes scattered throughout the application can manage very well.

Second, explain the name

1, section (Aspect)

  And a notification section tangent point composition, including both the transverse logic definitions, including the definition of the point of attachment, Spring AOP is responsible for the implementation of the frame section, the logic will cross section it defined woven into the designated section connection point.

2, the connection point (Joinpoint)

  Is the point of attachment can be inserted during application execution section (Aspect) a point. A specific location program execution: As classes begin initializing, after initialization class, the class before a method call, after call, after the method throws an exception.

3, the tangent point (Pointcut)

  Cut point is notified (the Advice) to be woven into (Weaving) specific location. Each program type has a plurality of connection points, such as a class has two methods, these methods are two connection points. So it is not one to one relationship between the tangent point and the connection point, a cut point may match a plurality of connection points. AOP by "tangent point" target a particular connection point.
  Specific example: such as driving through a highway, there are many outlets (connection points) on the highway, but we will not go out each outlet will be, will choose the exit (cut-off point) we need to open out .
  It can be understood as simple, are connected to each exit point, but that is the exit point of tangency we use. Each application has a plurality of positions for weaving notification, the positions are connection points. But only that specific location we have chosen is the cut-off point.

4, notice (Advice)

  It defines what the connection point, provide enhanced woven into the interface section. For example, logging, rights verification, transaction control, performance testing, error detection.
  Spring section may be used five types of notifications:
  pre-notification (the Before): call notification function before the target method is invoked;
  post-notification (the After): call notification after the target method is completed, this case does not concern a method of outputting What is;
  return notification (after-returning): called after successful execution of the target method notification;
  abnormal notice (after-throwing): after an exception is thrown in the target method call notification;
  around advice (Around): notification wrapped notified method, perform custom behavior before and after the method is notified of calls and call.

5, the notifier (Advisor)

  After completion of the section of the target method to enhance the design and design concerns, need an object to combine them, this action is completed Advisor.

6, proxy (Proxy)

  It provides a proxy to control access to the object to other objects. In some cases, an object is not suitable or not directly refer to another object, the proxy object can play the role of intermediary between the client and the target audience. Object proxy class itself is not real service, but by the relevant method calls the delegate class of objects to provide specific services.

Third, the difference between static and dynamic proxy agent

1, the static agent is usually only a proxy class, a plurality of dynamic proxy class that implements an interface in the proxy.
2, the static agent know in advance what you want to proxy is dynamic proxy agent does not know anything, only know at runtime.
3, the static agent, before the program is run, the proxy class .class file already exists; dynamic proxies, the program runs, the use of reflection to dynamically create together.

Fourth, the static proxy instance

1, for example a mobile phone to pay phone bill, TelecomOperator class service class.

package com.service;

/**
 * 定义一个电信运营商接口
 */
public interface TelecomOperator {
    //查询话费余额
    public void queryPhoneBal();

    //缴话费
    public void payPhoneBal();
}

2, TelecomOperatorImpl implementation class is

package com.controller;

import com.service.TelecomOperator;

public class TelecomOperatorImpl implements TelecomOperator {
    //查询话费余额
    @Override
    public void queryPhoneBal(){
        System.out.println("查话费方法...");
    }

    //缴话费
    @Override
    public void payPhoneBal(){
        System.out.println("缴话费方法...");
    }
}

3, TelecomOperatorProxy service proxy class

package com.controller;

import com.service.TelecomOperator;

/**
 * 第三方代理商
 *
 */
public class TelecomOperatorProxy implements TelecomOperator {
    private TelecomOperatorImpl telecomOperator;

    public TelecomOperatorProxy(TelecomOperatorImpl telecomOperator) {
        this.telecomOperator = telecomOperator;
    }

    //查询话费余额
    @Override
    public void queryPhoneBal(){
        System.out.println("切点:事务控制/日志输出");
        telecomOperator.queryPhoneBal();
        System.out.println("切点:事务控制/日志输出");
    }

    //缴话费
    @Override
    public void payPhoneBal(){
        System.out.println("切点:事务控制/日志输出");
        telecomOperator.payPhoneBal();
        System.out.println("切点:事务控制/日志输出");
    }
}

4, TelecomOperatorTest test class

package com.controller;

public class TelecomOperatorTest {
    public static void main(String[] args) {
        TelecomOperatorImpl telecomOperator = new TelecomOperatorImpl();
        TelecomOperatorProxy proxy = new TelecomOperatorProxy(telecomOperator);
        proxy.queryPhoneBal();
      	proxy.payPhoneBal();
    }
}

5, the console output

切点:事务控制/日志输出
查话费方法...
切点:事务控制/日志输出
切点:事务控制/日志输出
缴话费方法...
切点:事务控制/日志输出

Five, aop implementation principle (dynamic proxies)

1, JDK dynamic proxies

package com.controller;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK动态代理类
 */
public class TelecomOperatorJDKProxy implements InvocationHandler {
    private Object target;

    //返回代理对象
    public Object newProxy(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    /**
     * @param obj 目标对象代理类的实例
     * @param method 代理实例上调用父类方法的Method实例
     * @param args 代入到代理实例上方法参数值的数组
     */
    @Override
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable{
        Object result = null;
        System.out.println("切点:事务控制/日志输出");
        result=method.invoke(target,args);
        System.out.println("切点:事务控制/日志输出");
        return result;
    }
}
package com.controller;

import com.service.TelecomOperator;

public class TelecomOperatorJDKTest {
    public static void main(String[] args) {
        TelecomOperatorJDKProxy proxy = new TelecomOperatorJDKProxy();
        TelecomOperator telecomOperator = (TelecomOperator)proxy.newProxy(new TelecomOperatorImpl());
        telecomOperator.queryPhoneBal();
    }
}

Console output:

切点:事务控制/日志输出
查话费方法...
切点:事务控制/日志输出

2, Cglib dynamic proxy

package com.controller;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Cglib动态代理类
 */
public class TelecomOperatorCglibProxy implements MethodInterceptor {
    private Object target;//代理的目标对象

    //创建目标对象的代理对象
    public Object newProxy(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();//该类用于生成代理对象
        enhancer.setSuperclass(this.target.getClass());//设置父类
        enhancer.setCallback(this);//回调方法,设置回调对象为本身
        return enhancer.create();//创建代理对象
    }

    /**
     * @param obj 目标对象代理类的实例(增强过)
     * @param method 代理实例上调用父类方法的Method实例
     * @param args 代入到代理实例上方法参数值的数组
     * @param proxy 使用它调用父类的方法
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("切点:事务控制/日志输出");
        Object object = proxy.invokeSuper(obj, args);
        //Object object = proxy.invoke(target,args);
        System.out.println("切点:事务控制/日志输出");
        return object;
    }
}
package com.controller;

public class TelecomOperatorCglibTest {
    public static void main(String[] args) {
        TelecomOperatorCglibProxy proxy = new TelecomOperatorCglibProxy();
        TelecomOperatorImpl telecomOperatorimpl = (TelecomOperatorImpl)proxy.newProxy(new TelecomOperatorImpl());
        telecomOperatorimpl.queryPhoneBal();
    }
}

Console output:

切点:事务控制/日志输出
查话费方法...
切点:事务控制/日志输出

  The object (target) invoke a method call had not enhanced, the object (obj) invokeSuper method call has been enhanced, so will go again interceptor method MyMethodInterceptor, if it is a chain of interceptors, will once again walk in the interceptor chain. If you use invoke (obj, args) will be calling the cycle, resulting in an infinite loop, and throw an exception java.lang.StackOverflowError.

Sixth, the difference between the two kinds of dynamic proxy approach

  1, java dynamic proxy class is generated anonymous implement a proxy interface using reflection, InvokeHandler calls before calling a specific method to process. The dynamic proxy Cglib asm using open source packages, class files proxy object classes loaded in, processed by modifying a subclass bytecode.
  2, JDK dynamic proxy can generate a proxy class that implements the interface, but not for the class; Cglib agent is achieved for the class, the main class is specified to generate a sub-class, a method wherein the cover, because it is inherited, so that class or method is best not to be declared as final.
  3, Cglib a target class method generates two proxy method, a method of rewriting goal, and to achieve a proxy logic, there is a direct call to the target class method.

Guess you like

Origin blog.csdn.net/sinat_27933301/article/details/94198281