Spring framework Foundation (04): AOP tangent programming concept, demonstration of several implementation methods

Keywords: Java Spring Programming xml github

Source code: GitHub point here || GitEE point here

I. Introduction to AOP Foundation

1. Profile of section programming

AOP full name: Aspect Oriented Programming. A technique to realize the unified maintenance of program functions by precompiling and dynamic agent in runtime. Core function: it can isolate all parts of the business logic, reduce the coupling degree between all parts of the business logic, and improve the reusability and development efficiency of the program. AOP provides a new solution to replace inheritance and delegation, and it is more concise and clear to use, which is a hot idea in software development.

2. AOP terminology

(1) notification type: Advice

Pre notification [Before]: Before the target method is called;
Return notice [after returning]: after the target method is executed successfully;
Exception notification [after throwing]: after the target method throws an exception; 
Post notification [After]: After the completion of the target method;
Surround notification: surround notification before and after the execution of the target method;

(2) connection point: JoinPoint

A specific place for program execution, such as before and after class initialization, before and after method operation.

(3) tangent point: Pointcut

Join points are methods that may be intercepted under specified policies.

(4) section: Aspect

Cut plane is a combination of cut point and notice.

(5) Introduction

Special enhancements to add some properties and methods to the class.

(6) Weaving

The process of adding enhancements to a specific connection point of a target class. Compile time weaving, which requires the use of special compilers; class load time weaving, which requires the use of special class loaders; dynamic proxy weaving, which adds and enhances the generation of subclasses for the target class at runtime, Spring uses dynamic proxy weaving, while AspectJ uses compile time weaving and class load time weaving.

(7) Proxy

Class is woven by AOP to generate a result class, which is a proxy class that combines the original class and enhanced logic.

II. AOP programming mode

The case is based on the following categories:

public class Book {
    private String bookName ;
    private String author ;
}
public interface BookService {
    void addBook (Book book) ;
}
public class BookServiceImpl implements BookService {
    @Override
    public void addBook(Book book) {
        System.out.println(book.getBookName());
        System.out.println(book.getAuthor());
    }
}

1. JDK dynamic agent

public class BookAopProxyFactory {
    public static BookService createService() {
        // Target class
        final BookService bookService = new BookServiceImpl() ;
        // Section class
        final BookAspect bookAspect = new BookAspect();
        /*
         * Proxy class: combine the target class (pointcut) and the tangent class (notification)
         */
        BookService proxyBookService = (BookService) Proxy.newProxyInstance(
                BookAopProxyFactory.class.getClassLoader(),
                bookService.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method,
                                         Object[] args) throws Throwable {
                        // Pre execution
                        bookAspect.before();
                        // Methods for executing target classes
                        Object obj = method.invoke(bookService, args);
                        // Post execution
                        bookAspect.after();
                        return obj;
                    }
                });
        return proxyBookService ;
    }
}

2. CgLib bytecode enhancement

cglib, a bytecode enhancement framework, is used to enhance the target class by creating subclasses of the target class at runtime.

public class BookAopCgLibFactory {
    public static BookService createService() {
        // Target class
        final BookService bookService = new BookServiceImpl() ;
        // Section class
        final BookAspect bookAspect = new BookAspect();
        // Core agent class
        Enhancer enhancer = new Enhancer();
        // Determining parent class
        enhancer.setSuperclass(bookService.getClass());
        // Set callback function
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object proxy, Method method,
                                    Object[] args,
                                    MethodProxy methodProxy) throws Throwable {
                bookAspect.before();
                Object obj = method.invoke(bookService, args);
                bookAspect.after();
                return obj;
            }
        });
        BookServiceImpl proxyService = (BookServiceImpl) enhancer.create();
        return proxyService ;
    }
}

3. Spring semi-automatic agent

Spring creates a proxy object and obtains the proxy object manually from the spring container.

  • configuration file
<!-- Create target class -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- Create a tangent class -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- Create proxy class -->
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interfaces" value="com.spring.mvc.service.BookService" />
    <property name="target" ref="bookService" />
    <property name="interceptorNames" value="myAspect" />
</bean>
  • Section class
public class BookAopSpringHalf implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Method Before ...");
        Object obj = methodInvocation.proceed();
        System.out.println("Method After ...");
        return obj;
    }
}

4. Spring automatic agent

Get the target class from the spring container. If Aop is configured, spring will generate the agent automatically.

  • configuration file
<!-- Create target class -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- Create a tangent class -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- AOP Programming configuration -->
<aop:config proxy-target-class="true">
    <aop:pointcut expression="execution(* com.spring.mvc.service.*.*(..))"
                  id="myPointCut"/>
    <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>

5. Comprehensive test

@Test
public void test1 (){
    BookService bookService = BookAopProxyFactory.createService() ;
    Book book = new Book() ;
    book.setBookName("Spring actual combat");
    book.setAuthor("Craig Walls");
    bookService.addBook(book);
}
@Test
public void test2 (){
    BookService bookService = BookAopCgLibFactory.createService() ;
    Book book = new Book() ;
    book.setBookName("MySQL");
    book.setAuthor("Baron");
    bookService.addBook(book);
}
@Test
public void test3 (){
    String xmlPath = "spring-aop-half.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("proxyFactory");
    Book book = new Book() ;
    book.setBookName("The Dream of Red Mansion");
    book.setAuthor("Cao Xueqin");
    bookService.addBook(book);
}
@Test
public void test4 (){
    String xmlPath = "spring-aop-all.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("bookService");
    Book book = new Book() ;
    book.setBookName("Journey to the West");
    book.setAuthor("Wu Cheng en");
    bookService.addBook(book);
}

3. AspectJ aspect programming

1. Basic introduction

AspectJ is an AOP framework based on Java language. After Spring 2.0, support for AspectJ pointcut expression has been added. Through JDK5 annotation technology, it is allowed to define the pointcut directly in the class. The new version of Spring framework is recommended to use AspectJ to develop AOP programming.

2. XML configuration mode

  • Section class
public class BookAopAspectJ {
    public void myBefore(JoinPoint joinPoint){
        System.out.println("Advance notice:" + joinPoint.getSignature().getName());
    }
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("Post notice:" + joinPoint.getSignature().getName() + " , -->" + ret);
    }
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("Before surround notification");
        Object obj = joinPoint.proceed();
        System.out.println("Around the notice");
        return obj;
    }
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("Throw exception notification: " + e.getMessage());
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("Final notice");
    }
}
  • configuration file
<!-- Create target class -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- Create a tangent class -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopAspectJ" />
<!-- To configure AOP programming -->
<aop:config>
    <aop:aspect ref="myAspect">
        <aop:pointcut expression="execution(* com.spring.mvc.service.impl.BookServiceImpl.*(..))" id="myPointCut"/>
        <!-- Before advice-->
        <aop:before method="myBefore" pointcut-ref="myPointCut"/>
        <!-- Post notification -->
        <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
        <!-- Around Advice -->
        <aop:around method="myAround" pointcut-ref="myPointCut"/>
        <!-- Throw exception -->
        <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
        <!-- Final notice -->
        <aop:after method="myAfter" pointcut-ref="myPointCut"/>
    </aop:aspect>
</aop:config>
  • test method
@Test
public void test1 (){
    String xmlPath = "spring-aop-aspectj-01.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("bookService");
    Book book = new Book() ;
    book.setBookName("Romance of the Three Kingdoms");
    book.setAuthor("Luo Guanzhong");
    bookService.addBook(book);
}

3. Annotation scanning method

  • configuration file
<!-- Enable scanning of class annotations -->
<context:component-scan base-package="com.spring.mvc.service.impl" />
<!-- Determine AOP Commentary entry into force -->
<aop:aspectj-autoproxy />
<!-- Declaration section -->
<bean id="myAspect" class="com.spring.mvc.config.AuthorAopAspectJ" />
<aop:config>
    <aop:aspect ref="myAspect" />
</aop:config>
  • Annotation facet class
@Component
@Aspect
public class AuthorAopAspectJ {
    @Pointcut("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
    private void myPointCut(){
    }
    @Before("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("Advance notice:" + joinPoint.getSignature().getName());
    }
    @AfterReturning(value="myPointCut()" ,returning="ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("Post notice:" +
                joinPoint.getSignature().getName() + " , -->" + ret);
    }
    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("Before surround notification");
        Object obj = joinPoint.proceed();
        System.out.println("Around the notice");
        return obj;
    }
    @AfterThrowing(
            value="execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))",
            throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("Throw exception notification: " + e.getMessage());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("Final notice");
    }
}
  • test method
@Test
public void test2 (){
    String xmlPath = "spring-aop-aspectj-02.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    AuthorService authorService = (AuthorService) context.getBean("authorService");
    System.out.println("Author:"+authorService.getAuthor());
}

IV. source code address

GitHub·address
https://github.com/cicadasmile/spring-mvc-parent
GitEE·address
https://gitee.com/cicadasmile/spring-mvc-parent

Posted by caaronbeasley on Sun, 27 Oct 2019 17:46:03 -0700