spring learning 10-AOP

aop

About aop

AOP (Aspect Oriented Programming), that is, aspect-oriented programming, can be said to OOP (Object Oriented Programming, Object Oriented Programming) added and improved. OOP introduced as encapsulation, inheritance, polymorphism, etc. concept to build a hierarchy of objects, used to simulate the behavior of a common set. However, OOP allows developers to define vertical relationship, but are not suitable for transverse relationship defined, for example, the log function. Log code tends to spread laterally in all object hierarchy, the core object corresponding to the function it no relation to other types of code, such as security, exception handling, and continuity are also transparent so, this spread independent code is referred to throughout the transverse (cross cutting), in OOP design, which led to a lot of code repetition, to the detriment of reusable modules.

Contrary AOP technology, which uses a technique called "transverse", the internal cross-sectional decapsulates the object, and those that affect the behavior of the public classes encapsulated into a plurality of reusable modules, and named it " Aspect ", namely section. The so-called "cut", it simply is that nothing to do with business, but it is the responsibility of the business logic or common module called encapsulated, easy to duplicate code to reduce system and reduce the degree of coupling between modules, and facilitate future operability and maintainability.

Use "cross-cutting" technology, AOP the software system is divided into two parts: core concerns and crosscutting concerns . The main flow of business processes is a core concern, not part of the relationship is with crosscutting concerns. Features a crosscutting concern is that they often occur in many core concerns, and everywhere essentially similar, such as certification authority, log things. AOP is that the various concerns separation system, the core and crosscutting concerns separated.

AOP core concepts

  • Cross-cutting concerns: what methods were to intercept, how to deal with the interception, these concerns called crosscutting concerns. Such as logging, security, caching, transactions, and so ...
  • Section (ASPECT): class is an abstract object features, is the abstract section of crosscutting concerns. It can be said crosscutting concern is a special object is modular. That is, it is a class.
  • Connection point (JointPoint): point being intercepted, since Spring supports only a connection point type method, it is to point refers to the connection to be intercepted in the Spring, in fact, the point of attachment may also be field or constructors
  • Entry point (PointCut): to define a connection point of interception. He represents a group of local joint point, the joint point or by logic combination, or by wildcard, regular expressions, etc. together, which define the corresponding Advice to occur.
  • Notification (Advice): refers to the so-called notification refers to the connection point codes after the interception to be performed, a notification is divided into front, rear, abnormal end, surrounded by five notification. Section must be done. That is, it is a class method.
  • Audience (Target): proxy target object
  • Aspect process and other objects together and create Advice of: weaving (Weaving)
  • Proxy object (Proxy): Application objects created after notification to the target object.
  • Introducing (introduction): Under the premise of not modifying code, it may be introduced into the operation of adding methods or dynamic class fields

For example, an easy to understand :

Diagram

aop

Notification (Advice) type

  • Before advice: before
    the implementation of enhanced entry point before the execution method
  • Rear notification: after-returning
    pointcut enhanced embodiment after performing the normal method, and it can only perform one abnormality notification
  • Abnormality notification: after-throwing
    an exception occurs during the execution of the method after performing enhanced pointcut
  • The final notice: after
    whether an abnormality occurs regardless of entry point method is executed, it will perform at its back
  • Around advice: around
    it is a spring framework provides us with a way to control what time to enhance the implementation of the code in the code manually, under normal circumstances, around advice are used separately.

spring AOP support

Spring AOP proxy in Spring's IOC container is responsible for generation, management, and its dependencies are also responsible for the management by the IOC container .

Thus, the AOP agent may be used directly with other bean instance as a target container, this relationship may be provided dependency injection IOC containers. Spring create rules for agents:

1, use Java to create a dynamic proxy AOP proxy by default , so you can create an instance of any of the interfaces that the proxy

2, when the class is not required proxy interface agent, Spring CGLIB will switch to using a proxy , may also be used to force CGLIB

AOP programming is actually very simple thing, look at AOP programming, the programmer need only participate in three parts:

1, the definition of common business components

2, the definition of a starting point, a starting point may cross a plurality of business components

3, the definition enhancement processing, enhancement processing in the operation processing is the frame AOP component is woven into ordinary traffic

So the key is to define the entry points and the definition AOP enhancement processing program, once the entry point and define an appropriate enhancement processing, AOP AOP proxy frame is automatically generated, namely: the proxy object is a proxy object processing method = + enhancement method.

Using Spring AOP achieve

First of all write our business interface and implementation class

//抽象角色:增删改查业务
public interface UserService {
    int add();
    int delete();
    int update();
    void query();
}
//真实对象,完成增删改查操作的人
public
class UserServiceImpl implements UserService {
    @Override
    public int add() {
        System.out.println("增加一个用户");
        return 1;
    }

    @Override
    public int delete() {
        System.out.println("删除一个用户");
        return 1;
    }

    @Override
    public int update() {
        System.out.println("更新一个用户");
        return 1;
    }

    @Override
    public void query() {
        System.out.println("查找一个用户");
    }
}

Three ways to achieve the aop

1. implemented by spring API

Enhanced class

Enhanced write two classes, a pre-notification, post a notice, implement the interface provided by spring

//前置通知
public class BeforLog implements MethodBeforeAdvice {
    //method : 要执行的目标对象的方法
    //args : 被调用的方法的参数
    //target : 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
//        System.out.println( target.getClass().getName() + "的" + method.getName() + "方法被执行了");
        if(!method.getName().equals("query")){
            System.out.println("开启事务...");
        }
    }
}
//后置通知
public class AfterLog implements AfterReturningAdvice {
    //returnValue 返回值
    //method被调用的方法
    //args 被调用的方法的对象的参数
    //target 被调用的目标对象
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
//        System.out.println("执行了" + target.getClass().getName()
//                +"的"+method.getName()+"方法,"
//                +"返回值:"+returnValue);
        if(!method.getName().equals("query")){
            System.out.println("关闭事务...");
        }
    }
}

Profiles

Named beans1.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="beforLog" class="com.cong.pojo.BeforLog"/>
    <bean id="afterLog" class="com.cong.pojo.AfterLog"/>
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(* com.cong.pojo.UserServiceImpl.*(..))"/>
        <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
        <aop:advisor advice-ref="beforLog" pointcut-ref="userPointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="userPointcut"/>
    </aop:config>
</beans>

test

//spring的API
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.update();
    userService.delete();
}

result

查找一个用户
开启事务...
增加一个用户
关闭事务...
开启事务...
更新一个用户
关闭事务...
开启事务...
删除一个用户
关闭事务...

2. Customization Enhancements class

Analog transaction class

public class MyTransaction {
    public void before(){
        System.out.println("开启事务...");
    }
    public void afterReturning(){
        System.out.println("关闭事务...");
    }
    public void afterThrowing(){
        System.out.println("出现异常...");
    }
    public void after(){
        System.out.println("最终通知...");
    }
}

Abnormal manually add update () method

@Override
public int update() {
    int i  = 1/0;
    System.out.println("更新一个用户");
    return 1;
}

Profiles

Named beans2.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="transaction" class="com.cong.pojo.MyTransaction"/>
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(int com.cong.pojo.UserServiceImpl.*(..))"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="transaction">
            <aop:before method="before" pointcut-ref="userPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="userPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="userPointcut"/>
            <aop:after method="after" pointcut-ref="userPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

test

//自定义
@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans2.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.delete();
    userService.update();//会出现异常
}

result

Can be found, respectively, is performed by the way pre-notification method performed starting point, after advice or abnormality notification, inform the final

查找一个用户
开启事务...
增加一个用户
关闭事务...
最终通知...
开启事务...
删除一个用户
关闭事务...
最终通知...
开启事务...
出现异常...
最终通知...

3. Notes realized

Class section

@Aspect//标记为切面类
public class AnnotationPointcut {
    //前置通知
    @Before("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("开启事务...");
    }

    //后置通知
    @AfterReturning("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void afterReturning(){
        System.out.println("关闭事务...");
    }
    //异常通知
    @AfterThrowing("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void afterThrowing(){
        System.out.println("出现异常...");
    }
    //最终通知
    @After("execution(int com.cong.pojo.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("最终通知...");
    }
    //环绕通知
    //@Around
}

Profiles

Named beans3.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="userService" class="com.cong.pojo.UserServiceImpl"/>
    <bean id="annotationPointcut" class="com.cong.pojo.AnnotationPointcut"/>
    <!--开启注解支持,自动代理-->
    <aop:aspectj-autoproxy/>
</beans>

test

//注解的
@Test
public void test3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.query();
    userService.add();
    userService.delete();
    userService.update();//会出现异常
}

result

A bit mean that the notes to achieve, in the wrong order, the final notice more than the previous post notice

So if you want to use annotations to achieve aop, it is best to use around advice

查找一个用户
开启事务...
增加一个用户
最终通知...
关闭事务...
开启事务...
删除一个用户
最终通知...
关闭事务...
开启事务...
最终通知...
出现异常...

About extensions<aop:aspectj-autoproxy/>

By aop namespace <aop:aspectj-autoproxy />automatically create a proxy for the spring container configuration @aspectJ bean section of those statements, weaving section.

Of course, spring is still used internally AnnotationAwareAspectJAutoProxyCreatorfor automatic proxy creation work, but the specific implementation details have been <aop:aspectj-autoproxy />hidden up

<aop:aspectj-autoproxy />A proxy-target-classproperty, the default is false, the dynamic proxy indication jdk weaving enhanced. When the distribution is <aop:aspectj-autoproxy poxy-target-class="true"/>, the dynamic indication CGLib weaving reinforcing agent technology. But even if the proxy-target-class set to false, if the target class does not declare an interface, the spring will automatically use CGLib dynamic proxy.

4. About around advice

A spring surrounding the notification framework we may provide enhanced when the manual control method performed in the code.

For example, here enhanced custom class method implementation aop

Business class

Only one execution method

public class AroundAdviceService {
    public void doSomething(){
        System.out.println("do something...");
    }
}

Analog notification class

public class AroundLog {
    public void before(){
        System.out.println("前置通知...");
    }
    public void afterReturning(){
        System.out.println("后置通知...");
    }
    public void afterThrowing(){
        System.out.println("异常通知...");
    }
    public void after(){
        System.out.println("最终通知...");
    }
    public void around(){
        System.out.println("环绕通知...");
    }
}

Profiles

Named beans4.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="aroundLog" class="com.cong.pojo.AroundLog"/>
    <bean id="aroundAdviceService" class="com.cong.pojo.AroundAdviceService"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="userPointcut" expression="execution(void com.cong.pojo.AroundAdvice.doSomething())"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="aroundLog">
            <aop:before method="before" pointcut-ref="userPointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="userPointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="userPointcut"/>
            <aop:after method="after" pointcut-ref="userPointcut"/>
            <aop:around method="around" pointcut-ref="userPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

test

//环绕通知
@Test
public void test4(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
    AroundAdvice aroundAdvice = (AroundAdvice) context.getBean("aroundAdviceService");
    aroundAdvice.doSomething();
}

Abnormal results

Very strange results

前置通知...
环绕通知...
最终通知...
后置通知...

When commenting out aop inside around advice, the result is normal

前置通知...
do something...
后置通知...
最终通知...

Probe

problem:

When we configured the around advice, the entry point method is not executed, and the notification method executed.

the reason:

Surrounded by notification code dynamic contrast agents found around dynamic proxy notice a clear entry point method calls, and our code no.

solve:

Spring framework provides us with an interface: ProceedingJoinPoint. The interface has a way to proceed (), this method is equivalent to explicitly call the entry point method.

The interface may be notified as a parameter surrounded, during program execution, spring framework provides the interface implementation class for us to use for us.

Achieve around advice

Rewrite around advice

    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        Object res;
        try {
            Object [] args = proceedingJoinPoint.getArgs();//得到方法执行所需的参数
            before();//前置通知
            res = proceedingJoinPoint.proceed(args);//明确调用业务层方法(通过切入点表达式配置)
            afterReturning();//后置通知
            return res;
        } catch (Throwable throwable) {
            afterThrowing();//异常通知
            throw new RuntimeException(throwable);
        }finally {
            after();//最终通知
        }
    }

Configuration file, comment out all other notifications

<bean id="aroundLog" class="com.cong.pojo.AroundLog"/>
    <bean id="aroundAdvice" class="com.cong.pojo.AroundAdvice"/>
    <aop:config>
        <!--切入点表达式,即需要增强的方法-->
        <aop:pointcut id="pointcut" expression="execution(void com.cong.pojo.AroundAdvice.doSomething())"/>
        <!-- 配置切面,切面就是增强的过程中需要用到的类 -->
        <aop:aspect ref="aroundLog">
            <aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

Run again, the results of normal

前置通知...
do something...
后置通知...
最终通知...

Execution of the simulation aspect and advice

Handling from: https: //blog.csdn.net/qq_32331073/article/details/80596084

public class AspectAdviceInvokeProcess {
    public static void main(String[] args){
        try {
            //正常执行
            AspectInvokeProcess(false);
            System.out.println("=====分割线=====");
            //异常执行
            AspectInvokeProcess(true);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    /**
     * 切面执行过程
     * @param isException
     * @throws Exception
     */
    public static void AspectInvokeProcess(boolean isException) throws Exception{
        try {
            try {
                aroundAdvice(isException);
            } finally {
                afterAdvice();
            }
            afterReturningAdvice();
            return;
        } catch (Exception e) {
            afterThrowingAdvice(e);
            throw e;
            return;
        }   
    }
    
    /**
     * 环绕增强
     * @param isException
     * @throws Exception
     */
    private static void aroundAdvice(boolean isException) throws Exception {
        System.out.println("around before advice");
        try {
            JoinPoint_Proceed(isException);
        } finally {
            System.out.println("around after advice");
        }
    }
    
    /**
     * 编织后的接入点执行过程
     * @param isException
     */
    public static void JoinPoint_Proceed(boolean isException){
        beforeAdvice();
        targetMethod(isException);
    }
    
    /**
     * 前置增强
     */
    private static void beforeAdvice() {
        System.out.println("before advice");
    }

    /**
     * 目标方法
     * @param isException
     */
    private static void targetMethod(boolean isException) {
        System.out.println("target method 执行");
        if(isException)
            throw new RuntimeException("异常发生");
    }
    
    /**
     * 后置增强
     */
    private static void afterAdvice() {
        System.out.println("after advice");
    }

    /**
     * 正常返回增强
     */
    private static void afterReturningAdvice() {
        System.out.println("afterReturning");
    }

    /**
     * 异常返回增强
     * @param e
     * @throws Exception
     */
    private static void afterThrowingAdvice(Exception e) throws Exception {
        System.out.println("afterThrowing:"+e.getMessage());
    }
}

result

around before advice
before advice
target method 执行
around after advice
after advice
afterReturning
=====分割线=====
around before advice
before advice
target method 执行
around after advice
after advice
afterThrowing:异常发生
java.lang.RuntimeException: 异常发生

Guess you like

Origin www.cnblogs.com/ccoonngg/p/12026768.html