Spring AOP(注入AsPectJ切面)

一、介绍

AOP(Aspect Oriented Programming)。

        区别:OOP(Object Oriented Programming)和AOP(Aspect Oriented Programming)的区别:面向目标的区别,OOP面向名词领域,AOP面向动词领域。思想结构的区别,OOP是纵向结构,AOP是横向结构。注重方面的区别,OOP注重业务逻辑单元的划分,AOP偏重业务处理过程的某个步骤或阶段。

        AOP功能:AOP面向切面编程是对OOP面向对象编程的一种补充。对业务逻辑各个部分进行隔离,降低功能之间的耦合度,提高代码复用率。主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理,权限管理、缓存管理、资源池管理等。

        AOP代理:AOP实现的关键是代理模式,AOP代理分为静态代理和动态代理。静态代理指AspectJ,在编译阶段生成AOP代理类,也称编译时增强。动态代理在运行时用JDK动态代理和CGLIB在内存中临时生成AOP代理类,也称为运行时增强。

        两种动态代理:Spring会使用JDK动态代理只支持实现类(实现了某个接口,委托类)的代理。否则,会使用CGLib来实现动态代理。CGLib动态代理是通过字节码底层继承被代理类(不能被final关键字所修饰)来实现。

        CGLIB(Code Generator Library):是一个强大的、高性能的代码生成库。它可以在运行期扩展Java类与实现Java接口。CGLIB以ASM为基础, 对ASM的功能进行了扩展和封装,提供了更友好的API。在AOP框架中,用来提供方法拦截操作。在Hibernate中,用来实现PO(Persistent Object 持久化对象)字节码的动态生成。

        AspectJ:Spring AOP的切入点类型只能是方法,AspectJ可以是多种类型(如构造方法)。AspectJ也实现了AOP的功能,且其实现简捷,使用方便,功能健全,支持注解式开发。所以,Spring将AspectJ基础到框架中,与Spring AOP相互独立。

        Aop的专业术语:

                Aspect(切面):在Aspect中会包含着一些Pointcut以及相应的Advice。
                Pointcut(切入点):定义了相应Advice要发生的地方。
                Advice(通知):Advice定义了在Pointcut(切入点)具体要做的操作。
                Weaving(织入):将Aspect和其他对象连接起来。   

        Advice(通知)的5中类型:  

                before advice, 前置。
                after return advice, 后置(出错不执行)。
                after throwing advice, 后置(出错才执行)。
                after(final) advice, 后置(怎么都执行)。
                around advice, 前后都执行。

二、代码

1、pom.xml。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zxj</groupId>
    <artifactId>zxj-spring</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>zxj-spring</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <spring.version>4.3.18.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <!--Spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!--编译aspect的插件,将.aj编译为class文件,不然spring创建时找不到类-->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <complianceLevel>1.8</complianceLevel>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
        </plugins>
    </build>
</project>

插件aspectj-maven-plugin可以将.aj文件编译成.class文件,否则会提示找不到切面类的信息。可以对下载的插件aspectj-maven-plugin进行测试,双击idea右侧maven中的aspectj:compile或者aspectj:test-compile。如果下运行正常,即为成功。否则,要到maven仓库中将下载不全的包删除了,重新下载。

2、主流程代码(在单元测试中)。

package com.zxj;

import com.zxj.dao.entity.User;
import com.zxj.dao.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

//junit测试单元要使用下面两个注解,否则@Autowwire为null
@RunWith(SpringJUnit4ClassRunner.class)//可能会报junit版本过低的错误,将其变高就可以了
@ContextConfiguration("classpath:spring.xml")
public class AopTest {

    @Resource(name = "userService")
    private IUserService userService;
    @Resource(name = "childService")
    private IUserService childService;

    @Test
    public void aopTest2() {
        User user = new User();
        user.setAge(14);
        user.setName("小白");
        userService.printInfo(user);
        System.out.println();
        childService.printInfo(user);
    }
}

3、Spring.xml代码。

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

    <!--要扫描包-->
    <context:component-scan base-package="com.zxj"/>


    <!-- AOP 注入AspectJ切面 -->

    <bean class="com.zxj.test.aop.UserAspectInject" factory-method="aspectOf"/>

</beans>

4、 Aspect(切面):在Aspect中会包含着一些Pointcut以及相应的Advice。文件后缀为 .aj(十分重要)

package com.zxj.test.aop;

/**
 * AOP 注入AspectJ切面
 * <p>
 * Aspect(切面,拦截器):在Aspect中会包含着一些Pointcut以及相应的Advice。
 */
public aspect UserAspectInject {
    public UserAspectInject() {
    }
    /**
     * Pointcut(切入点):定义了相应Advice要发生的地方。
     * <p>
     * 定义切入点的常用的两种方式:
     * 1、使用正则表达式。
     * 2、使用AspectJ表达式(Https://www.iteye.com/blog/jinnianshilongnian-1415606)。
     */
    pointcut printInfo():execution(* com.zxj.dao.service.IUserService.printInfo(..));
    pointcut constructEntity():execution(com.zxj.dao.entity.User.new());


    /**
     * Advice定义了在Pointcut(切入点)具体要做的操作。
     * <p>
     * 切入点在AOP中有多种类型,但在Spring中只有方法类型。
     * <p>
     * before advice, 前置。
     * after return advice, 后置(出错不执行)。
     * after throwing advice, 后置(出错才执行)。
     * after(final) advice, 后置(怎么都执行)。
     * around advice, 环绕(前后都执行)。
     */

    before():printInfo(){
        System.out.println("\n------printInfo()方法的前置------");
    }

    after():printInfo(){
        System.out.println("------printInfo()的后置------\n");
    }

    before():constructEntity(){
        System.out.println("\n------new User()时候的前置------");
    }

    after():constructEntity(){
        System.out.println("-------new User()时候的后置------\n");
    }
}

5、User.java、IUserService.java、UserServiceImpl.java、ChildServiceImpl.java。

前面的文章:Spring AOP(经典的基于代理)Spring AOP(AspectJ注解)都有,就不重复写入了。

三、结果

1、打印的完整结果。

2、我们在切入点为构造方法,即new User()的地方打下断掉。发现程序运行到这里的时候,没有打印任何日志。

3、将调试的地方换到下一步的地方,即在user.setAge(14)的地方,发现触发了aspect切面中的advice通知。由此可以看出,注入AspectJ切面的切入点可以选择在构造方法上。

发布了67 篇原创文章 · 获赞 401 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/qq_36511401/article/details/103514517