The Spring Learning Road 3-AOP and Three Ways to Implement AOP

AOP

Aspect-oriented programming (AOP), also translated as Aspect-oriented programming and Profile-oriented programming, is a program design idea in computer science. It aims to further separate cross-cutting concerns from business entities to improve the modularity of program code.By adding an additional Advice mechanism to the existing code, code blocks declared as "Pointcut" can be uniformly managed and decorated, such as "adding background logs for methods that start with'set*'for all method names".This idea enables developers to add functionality (such as logging) that is less closely related to the core business logic of the code to their programs without compromising the readability of the business code.The facet-oriented programming design idea is also the basis of facet-oriented software development.

Maven Dependency

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

Implementation 1: Native Spring API interface

public interface UserService {
    void add();
    int delete();
    void query();
    int update();
}

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("function:add()");
    }

    @Override
    public int delete() {
        System.out.println("function:delete()");
        return 0;
    }

    @Override
    public void query() {
        System.out.println("function:query()");
    }

    @Override
    public int update() {
        System.out.println("function:update()");
        return 0;
    }
}

//log before method execution
public class BeforeLog implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {

        System.err.println("method before log" + target.getClass().getName() + method.getName());
    }
}

//log after method execution
public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.err.println("method before log" + target.getClass().getName() + "-->" + method.getName() + "---return:" + returnValue);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="log1" class="com.youzi.log.BeforeLog"/>
    <bean id="log2" class="com.youzi.log.AfterLog"/>
    <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>

    <!--To configure AOP-->
    <aop:config>
        <aop:pointcut id="pointcut1" expression="execution(int com.youzi.service.UserServiceImpl.*(..))"/>
        <aop:pointcut id="pointcut2" expression="execution(void com.youzi.service.*.add(..))"/>
        <aop:advisor advice-ref="log1" pointcut-ref="pointcut1"/>
        <aop:advisor advice-ref="log2" pointcut-ref="pointcut2"/>
    </aop:config>
</beans>

execution() tangent function syntax:

Execution (return type package name. class name. method name (parameter type))
  • You can also use the * sign to indicate all types.

  • Class names can also use * instead of representing all classes below the package

  • *(.): This asterisk denotes the method name, * denotes all methods, parentheses are the method's parameters, and two points denote any parameters.

Implementation 2: Custom class

The first implementation implements adding logs before or after methods, but each implementation of a function requires an interface, which can be written in a class by

public class MethodLog {
    public void beforeMethod() {
        System.out.println("Before method execution");
    }

    public void afterMethod() {
        System.out.println("After method execution");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="MethodLog" class="com.youzi.log.MethodLog"/>
    <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>

    <aop:config>
        <aop:aspect ref="MethodLog">
            <aop:pointcut id="poindcut1" expression="execution(* com.youzi.service.*.*(..))"/>
            <aop:before method="beforeMethod" pointcut-ref="poindcut1"/>
            <aop:after method="afterMethod" pointcut-ref="poindcut1"/>
        </aop:aspect>
    </aop:config>
</beans>

Although the above method simplifies the code, it currently does not seem possible to retrieve the execution method information through reflection as in the first way.

Mode 3: Using Notes

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="MethodLog" class="com.youzi.log.MethodLog"/>
    <bean id="userservice" class="com.youzi.service.UserServiceImpl"/>
    <!--stay xml How annotations are declared in-->
    <aop:aspectj-autoproxy/>
</beans>
@Aspect 
public class MethodLog {
    @Before("execution(* com.youzi.service.UserServiceImpl.*(..))")
    public void beforeMethod() {
        System.out.println("Method Execution First 1");
    }

    @After("execution(* com.youzi.service.UserServiceImpl.*(..))")
    public void afterMethod() {
        System.out.println("Method 1 after execution");
    }

    @Around("execution(* com.youzi.service.UserServiceImpl.update(..))")
    public int aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.err.println("Before Surround");
        System.err.println(joinPoint.getSignature());
        Object proceed = joinPoint.proceed();
        System.err.println("After Surround");
        return Integer.valueOf((Integer) proceed);
    }

}

Unify test code to

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userservice", UserService.class);
userService.query();
userService.add();
userService.delete();
userService.update();

Tags: Java Spring xml Programming encoding

Posted on Thu, 19 Mar 2020 15:04:54 -0400 by Fed51