初识Spring AOP

概念AOP介绍AOP核心概念AOP标签配置元素AOP实现步骤实例基于XML基于注解java

概念

AOP介绍

AOP(Aspect-Oriented Programming:面向切面编程)可以将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减小系统的重复代码,下降模块间的耦合度,并有利于将来的可拓展性和可维护性。web

Spring AOP 就是基于动态代理的,若是要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去建立代理对象,而对于没有实现接口的对象,就没法使用 JDK Proxy 去进行代理了,,这时候 Spring AOP会使用 Cglib 生成一个被代理对象的子类来做为代理,以下图所示:spring

除此以外还有一种状况,若是被代理对象实现了接口,能够强制使用 Cglib 实现 AOP。express

固然你也可使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。Spring AOP 基于注解配置的状况下,须要依赖于 AspectJ 包的标准注解,可是不须要额外的编译以及 AspectJ 的织入器,而基于 XML 配置不须要,因此 Spring AOP 只是复用了 AspectJ 的注解,并无其余依赖 AspectJ 的地方。apache

使用 AOP 以后咱们能够把一些通用功能抽象出来,在须要用到的地方直接使用便可,这样大大简化了代码量。咱们须要增长新功能时也方便,这样也提升了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。编程

当 Spring 须要使用 @AspectJ 注解支持时,须要在 Spring 配置文件中以下配置:mvc

<aop:aspectj-autoproxy/>
复制代码

而关于强制使用 Cglib,能够经过在 Spring 配置文件以下实现:app

<aop:aspectj-autoproxy proxy-target-class="true"/>
复制代码

proxy-target-class 属性值决定是基于接口的仍是基于类的代理被建立,默认为 false。若是 proxy-target-class 属性值被设置为 true,那么基于类的代理将有效(这时须要 Cglib 库)。反之是基于接口的代理(JDK的动态代理)。框架

因此,虽然使用了 AspectJ 的 Annotation,可是并无使用它的编译器和织入器。其实现原理是 JDK 动态代理或 Cglib,在运行时生成代理类。maven

AOP核心概念

链接点:JoinPoint,就是要被拦截的方法

切入点:PointCut,定义在哪些类,哪些方法上切入(拦截)

通知:Advice,在拦截到链接点以后要执行的代码,通知主要有五种,前置通知,后置通知,异常通知,最终通知和环绕通知。

切面:AspectJ,就是切入点加上通知

织入:weaving,把切面加入对象,并建立出代理对象的过程。

AOP标签配置元素

aop:aspect: 定义一个切面
aop:before: 定义一个前置通知
aop:after: 定义一个后置通知
aop:around: 定义一个环绕通知
aop:after-returning : 定义一个返回通知
aop:after-throwing :定义一个异常通知
aop:config: 顶层的aop配置元素
aop:pointcut: 定义切入点

AOP实现步骤

  1. 定义普通的业务组件;
  2. 定义切入点;
  3. 定义加强处理,也就是在AOP框架中为普通的业务逻辑织入的处理动做。

实例

基于XML

继续使用租房的案例,接下来新建一个切面类:

public class ProxyXML {

    public void seeHouse(){
        System.out.println("带客户看房子");
    }

    public Object getMoney(ProceedingJoinPoint p){
        System.out.println("租房.....before");
        Object o = null;
        try{
            o = p.proceed();
        }catch(Throwable e){
            e.printStackTrace();
        }
        System.out.println("租房.....after");
        return o;
    }

    public void fare(){
        System.out.println("收取中介费");
    }
}
复制代码

配置文件:

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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"
>



    <bean id="host" class="com.msdn.bean.Host" />

    <bean id="proxy" class="com.msdn.aop.ProxyXML" />

    <!--Spring基于Xml的切面-->
    <aop:config>
        <!--定义切点函数-->
        <aop:pointcut id="rentPointCut" expression="execution(* com.msdn.bean.Host.rent())"/>

        <!-- 定义切面 order 定义优先级,值越小优先级越大-->
        <aop:aspect ref="proxy" order="0">
            <!--前置通知-->
            <aop:before method="seeHouse" pointcut-ref="rentPointCut" />
            <!--环绕通知-->
            <aop:around method="getMoney" pointcut-ref="rentPointCut" />
            <!--后置通知-->
            <aop:after method="fare" pointcut-ref="rentPointCut" />
        </aop:aspect>
    </aop:config>

</beans>
复制代码

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">

    <parent>
        <artifactId>spring_study</artifactId>
        <groupId>com.msdn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring-chap3</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
    </dependencies>


</project>
复制代码

测试代码:

@Test
public void aopTest(){
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");

    Object host = context.getBean("host");
    Rent o = (Rent) host;
    o.rent();
}
复制代码

执行结果为:

带客户看房子
租房.....before
房屋出租
租房.....after
收取中介费
复制代码

基于注解

切面类:

@Order(0)
@Aspect
@Component
public class ProxyAnnotation {

    @Before(value = "execution(* com.msdn.bean.Host.rent())")
    public void seeHouse(){
        System.out.println("带客户看房子");
    }

    @Around(value = "execution(* com.msdn.bean.Host.rent())")
    public Object getMoney(ProceedingJoinPoint p){
        System.out.println("租房.....before");
        Object o = null;
        try{
            o = p.proceed();
        }catch(Throwable e){
            e.printStackTrace();
        }
        System.out.println("租房.....after");
        return o;
    }

    @After(value = "execution(* com.msdn.bean.Host.rent())")
    public void fare(){
        System.out.println("收取中介费");
    }
}
复制代码

切面类版本二:

@Order(0)
@Aspect
@Component
public class ProxyAnnotation2 {

    @Pointcut("execution(* com.msdn.bean.Host.rent())")
    public void rentPointCut(){

    }

    @Before(value = "rentPointCut()")
    public void seeHouse(){
        System.out.println("带客户看房子");
    }

    @Around(value = "rentPointCut()")
    public Object getMoney(ProceedingJoinPoint p){
        System.out.println("租房.....before,优先级更高");
        Object o = null;
        try{
            o = p.proceed();
        }catch(Throwable e){
            e.printStackTrace();
        }
        System.out.println("租房.....after");
        return o;
    }

    @After(value = "rentPointCut()")
    public void fare(){
        System.out.println("收取中介费");
    }
}
复制代码

配置文件:

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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.msdn.bean,com.msdn.aop" />
    <aop:aspectj-autoproxy proxy-target-class="true" />

</beans>
复制代码

测试代码:

    @Test
    public void aopTest(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop2.xml");

        Object host = context.getBean("host");
        Rent o = (Rent) host;
        o.rent();
    }
复制代码

执行结果为:

租房.....before
带客户看房子
房屋出租
租房.....after
收取中介费
复制代码
相关文章
相关标签/搜索