Spring Learning - Aspect Oriented Programming (AOP)

Keywords: Spring xml Java Programming

Spring - Aspect Oriented Programming (AOP)

1. The concept of tangent

Cross-cutting concerns, special classes that can be modularized.

Vernacular: Defines the code that I want to execute in the specified place when the program is executed.

2. AOP terminology

  • Advice: All-round work. It's "when and what to do"
    • There are five types: Before, After, After-returning, After-throwing and Around.
  • Join Point: All points that can be inserted into a tangent when executing a program
  • Point Cut: Where is it used to specify the scope of notification execution?
  • Aspect: The combination of notification and tangent points. All aspects are defined in common.
  • Introduction: Introduction allows us to add new methods and attributes to existing classes.
  • Weaving: The process of applying a facet to a target object and creating a new proxy object. The facet is woven into the target object at a specified join point.

3. Vernacular Understanding

Define a facet. Define the code that executes the facet I write when I want to execute it somewhere.

So I need to define an AOP class:
1. I need it to be declared as a faceted class (implemented on the class with the @Aspect annotation)
2. I need to specify what type of things and what to do. (Five notifications and business code)
3. I need to define a tangent point to specify where I am executing the content of the tangent class (the tangent point).
4. I need to configure my project so that the sections can be recognized. (@Component and <aop:aspectj-autoproxy/>)

4. Simple Code Implementation

  • Need dependence

    <!-- spring-aspects Neutral dependent aspectjweaver yes aspectj The weaving bag -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
    </dependency>
    
    <!-- While I was testing,The following dependencies are not necessary --> 
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
    </dependency>
    <!-- aspectjrt Bag is aspectj Of runtime package -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    
    
  • Tangential class

    @Aspect  //Statement Aspects
    @Component //Add containers
    public class LogAspect {
    
        protected static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
    
        //Define a cut point (Write 1)
        @Pointcut("execution(public * com.min.spring.service..*(..))")
        public void pt1(){}
    
        //Notification specifies the tangent point defined above
        @Before("pt1()")
        public void start(JoinPoint joinPoint) {
            logger.info("service start====" + joinPoint.getSignature().getName());
        }
    
        @After("pt1()")
        public void after(JoinPoint joinPoint) {
            logger.info("service after====" + joinPoint.getSignature().getName());
        }
    
        //It is not necessary to define the cut-off point directly in the notification.
        @Before("execution(public * com.min.spring.controller..*(..))")
        public void cstart(JoinPoint joinPoint) {
            logger.info("controller start====" + joinPoint.getSignature().getName());
        }
    
        @After("execution(public * com.min.spring.controller..*(..))")
        public void cafter(JoinPoint joinPoint) {
            logger.info("controller after====" + joinPoint.getSignature().getName());
        }
    }
    
  • Configuration xml (spring-context.xml and spring-mvc.xml are marked with aspectJ automatic proxy enabled)

    <aop:aspectj-autoproxy/>
    
  • results of enforcement

    2019-08-14 17:45:06,345 8602   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - controller start====login
    2019-08-14 17:45:06,346 8603   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - service start====login
    2019-08-14 17:45:06,346 8603   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - service start====findByUsername
    2019-08-14 17:45:06,517 8774   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - service after====findByUsername
    2019-08-14 17:45:06,518 8775   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - service after====login
    2019-08-14 17:45:06,518 8775   [nio-8080-exec-7] INFO  om.min.spring.aspect.LogAspect  - controller after====login
    2019-08-14 17:45:06,540 8797   [nio-8080-exec-8] INFO  om.min.spring.aspect.LogAspect  - controller start====index
    2019-08-14 17:45:06,548 8805   [nio-8080-exec-8] INFO  om.min.spring.aspect.LogAspect  - controller after====index
    

5. Common Writing of Point Cut

//Execution of any public method:
execution(public * *(..))

//Execution of any method whose name begins with set:
execution(* set*(..))

//Execution of any method defined by the AccountService interface:
execution(* com.xyz.service.AccountService.*(..))

//Execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))

//Execution of any method defined in a service package or its subpackage:
execution(* com.xyz.service..*.*(..))

//Any join point in the service package (only method execution in Spring AOP):
within(com.xyz.service.*)

//Any join point in a service package or its subpackage (only method execution in Spring AOP):
within(com.xyz.service..*)

//Any join point of the proxy object that implements the AccountService interface (only method execution in Spring AOP):
this(com.xyz.service.AccountService)

//Any join point of the target object that implements the AccountService interface (only method execution in Spring AOP):
target(com.xyz.service.AccountService)

//Any parameter that accepts only one parameter and passes in at runtime is the connection point of the Serializable interface (only method execution in Spring AOP):
args(java.io.Serializable)
//Note that the pointcut given in the example is different from execution (** (Java. io. Serializable). The args version matches only when the incoming parameter is Serializable at dynamic runtime, while the execution version matches when the method signature declares that there is only one parameter of type Serializable.

//There is an arbitrary join point for the @Transactional annotation in the target object (only method execution in Spring AOP):
@target(org.springframework.transaction.annotation.Transactional)

//Any type of target object declaration has a join point for the @Transactional annotation (only method execution in Spring AOP):
@within(org.springframework.transaction.annotation.Transactional)

//Any method of execution has one @Transactional Connecting Points of Annotations (in the ___________ Spring AOP Only method execution:
@annotation(org.springframework.transaction.annotation.Transactional)

//Any one accepts only one parameter and the type of parameter passed in at run time has a join point with the @Classified annotation (only method execution in Spring AOP):
@args(com.xyz.security.Classified)

//Any join point on a Spring bean called tradeService (only method execution in Spring AOP):
bean(tradeService)

//Any join point on the Spring bean of the name matching wildcard expression * Service (only method execution in Spring AOP):
bean(*Service)

//Among them, this, tagart, args, @target, @with, @annotation and @args are more commonly used in binding forms.

Common problem

1. The parent-child relationship between Spring MVC container and Spring container causes Aspect to fail

Description:

  • The tangent points defined in Aspect include the Controller layer and Service layer
  • There are father and son containers, Spring MVC containers and Spring containers
  • Objects of the defined Aspect class are placed in the parent container
  • Enabling aspectJ automatic proxy is only in spring-context.xml or spring-mvc.xml
  • Only partially effective or ineffective slice execution

Solution 1:

spring-context.xml and spring-mvc.xml are marked with aspectJ automatic proxy enabled

    <! - Enable aspectJ automatic proxy - >
    <aop:aspectj-autoproxy/>

Solution 2:

Do not subcontract scanning in spring-context.xml and spring-mvc.xml.

 <context:component-scan base-package="com.min.spring">
 </context:component-scan>

Reason:

1. The influence of Spring MVC container and Spring container

In general project configuration web.xml, Spring container is generated by ContextLoaderListener, while Spring MVC container is loaded by Dispatcher Servlet, Spring container is parent container, Spring MVC container is child container.

Subcontainers (Spring MVC containers) can access the contents of parent containers (Spring containers), but not vice versa.

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-context*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

<!--To configure Spring Of Servlet The distributor handles all HTTP Request and response-->
    <servlet>
        <servlet-name>springServlet</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:/spring-mvc*.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

When scanning a package, the parent container (Spring container) scans annotations other than @Controller.

The Spring MVC container scans only @Controller annotations.

spring-context.xml

 <context:component-scan base-package="com.min.spring">
     <context:exclude-filter type="annotation"
                             expression="org.springframework.stereotype.Controller"/>
 </context:component-scan>

spring-mvc.xml

<!-- Use Annotation automatic logon Bean,Scanning only @Controller use-default-filters Must be set to false-->
<context:component-scan base-package="com.min.spring"
                        use-default-filters="false">
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

If you write a section with both Controller and Service layers, both parent and child containers need to have aspectJ automatic proxy enabled.

If only in one xml, the generated automatic proxy is only part of the corresponding container.

So start the aspectJ automatic proxy in the xml of both containers.

spring-context.xml and spring-mvc.xml

    <! - Enable aspectJ automatic proxy - >
    <aop:aspectj-autoproxy/>

If only in one xml, the generated automatic proxy is only part of the corresponding container.

Posted by buddhika2010 on Wed, 14 Aug 2019 03:21:05 -0700