Spring--Aop

spring--Aop

Aop核心术语与概念

  • 通知(Advice): 定义通知类型和何时执行通知

Before(前置通知):目标方法调用前的通知;
After(后置通知):目标方法调用完成后的通知;
After-Returning (返回通知):目标方法执行返回后调用;
After-Throwing(异常通知):目标方法抛出异常后调用的通知;
Around(环绕通知):包含方法调用的前后返回以及异常执行的一系列行为。

  • 连接点(Join point): 通知执行的时机
  • 切点(Pointcut): 在何处执行通知
  • 切面(Aspect): 切点+通知
  • 引入(Introduction):向现有的内添加新的方法或者属性
  • 织入(Weaving): 把切面引用到目标对象并创建新的代理对象的过程

织入时间:
AspectJ---编译期
类加载期 --- classLoader --- AspectJ5
Spring --- 运行时织入

实现方式

1.代理Aop&Spring自动代理模式

package com.spring.study.aop.hunter;

/**
 * 定义一个行为
 */
public interface HunterAction {
    void findAnimal();
}

package com.spring.study.aop.hunter;

/**
 * 目标方法
 */
public class Hunter implements HunterAction {
    @Override
    public void findAnimal() {
        System.out.println("Hunter find animal...");
        //throw new RuntimeException("throw aop...");

    }
}

package com.spring.study.aop.hunter;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

/**
 * 定义通知类型
 */
public class HunterAdvices implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
    /**
     *
     * @param o 返回值
     * @param method 代理方法
     * @param objects 参数列表
     * @param o1 目标方法
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("The hunter caught a rabbit");
    }

    /**
     *
     * @param method 代理方法
     * @param objects 参数列表
     * @param o 目标方法
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("The hunter went to the forest");
    }

    public void afterThrowing(Method method,Object[] args,Object target,RuntimeException e) throws Throwable{
        System.out.println("The hunter lost his way reason is " + e);
    }
}

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: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">
    <context:component-scan base-package="com.spring.study.aop.hunter"/>
    <bean id="hunter" class="com.spring.study.aop.hunter.Hunter"/>
    <bean id="hunterAdvices" class="com.spring.study.aop.hunter.HunterAdvices"/>
<!--创建代理对象-->
    <bean id="hunterProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="hunter"/>
        <property name="interceptorNames" value="hunterAdvices"/>
        <property name="proxyInterfaces" value="com.spring.study.aop.hunter.HunterAction"/>
    </bean>

    <!--定义切点-->
    <bean id="hunterPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="pattern" value=".*findAnimal"/>
    </bean>
<!--定义通知-->
    <bean id="hunterAdvice" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="hunterAdvices"/>
        <property name="pointcut" ref="hunterPointcut"/>
    </bean>


<!--    自动代理-->
<!--    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>-->
<!--    <bean id="hunterAdvice" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">-->
<!--        <property name="advice" ref="hunterAdvices"/>-->
<!--        <property name="patterns" value=".*findAnimal"/>-->
<!--    </bean>-->
</beans>

package com.spring.study.bean.aop.hunter;

import com.spring.study.aop.hunter.HunterAction;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:aop/aop-proxy.xml")
@Slf4j
public class HunterTest {
    //非自动代理模式,显式指定为代理类
    @Autowired
    @Qualifier("hunterProxy")
    private HunterAction hunterAction;

    @Test
    public void testHunterAop(){
        hunterAction.findAnimal();
    }
}

2.pojo切面

引入Aspect依赖

 <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>x

例行惯例定义行为和主题

package com.spring.study.aop.pojo;

public interface DoAction {
    void action();
}

package com.spring.study.aop.pojo;

public class SomeOne implements DoAction {
    @Override
    public void action() {
        System.out.println("Do someting...");
    }
}

package com.spring.study.aop.pojo;

/**
 *自定义Pojo切面
 */
public class PojoAspect {
    public void before(){
        System.out.println("init...");
    }

    public void afterReturning(){
        System.out.println("finish...");
    }
}

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:context="http://www.springframework.org/schema/context"
       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/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.spring.study.aop.pojo"/>
<!--target-->
<bean id="someOne" class="com.spring.study.aop.pojo.SomeOne"/>
<!--aspect-->
    <bean id="pojoAspect" class="com.spring.study.aop.pojo.PojoAspect"/>
<!--    aop 切入点切面-->
    <aop:config>
        <aop:pointcut id="someOnePointcut" expression="execution(* com.spring.study.aop.pojo.DoAction.action(..))"/>
        <aop:aspect ref="pojoAspect">
            <aop:before method="before" pointcut-ref="someOnePointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="someOnePointcut"/>
        </aop:aspect>
    </aop:config>
</beans>
package com.spring.study.bean.aop.pojo;

import com.spring.study.aop.pojo.DoAction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:aop/aop-pojo.xml")
public class SomeOneTest {
    @Autowired
    private DoAction doAction;
    @Test
    public void testPojoAop(){
        doAction.action();
    }
}

3.Aspect注解形式(推荐)

package com.spring.study.aop.perform;

public interface Performance {
    void perform();
    void performOrder(int order);
}

package com.spring.study.aop.perform;

import org.springframework.stereotype.Component;

@Component
public class StartPerform implements Performance {
    @Override
    public void perform() {
        System.out.println("Performing...");
    }

    @Override
    public void performOrder(int order) {
        System.out.println("perform order is " + order);
    }
}

package com.spring.study.aop.perform;

import org.aspectj.lang.annotation.*;

@Aspect
public class Audience {
    @Pointcut("execution(* com.spring.study.aop.perform.Performance.perform(..))")
    public void pointcut(){}

    @Before("pointcut()")
    public void silenceCellPhones(){
        System.out.println("silence cell phone...");
    }

    @Before("pointcut()")
    public void takeSeat(){
        System.out.println("taking seat...");
    }

    @AfterReturning("pointcut()")
    public void applause(){
        System.out.println("applause...");
    }

    @AfterThrowing("pointcut()")
    public void demandRefund(){
        System.out.println("Demanding a refund...");
    }

}

环绕通知

package com.spring.study.aop.perform;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AroundPerform {
    @Pointcut("execution(* com.spring.study.aop.perform.Performance.perform(..))")
    public void pointcut(){}
    @Around("pointcut()")
    public void start(ProceedingJoinPoint pjp){
        try {
            System.out.println("Do something before perform");
            pjp.proceed();
            System.out.println("After perform...");
        } catch (Throwable throwable) {
            System.out.println("AfterThrowing...");
        }
    }
}

带入参的情况

package com.spring.study.aop.perform;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class OderAop {
    @Pointcut("execution(* com.spring.study.aop.perform.Performance.performOrder(int)) && args(order)")
    private void pointcutWithArg(int order){}

    @Before("pointcutWithArg(order)")
    public void beforeStart(int order){
        System.out.println("perform order " + order);
    }
}

配置类

package com.spring.study.aop.perform;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class PerformConfig {
    @Bean
    public Audience audience(){
        return new Audience();
    }

    @Bean
    public OderAop oderAop(){
        return new OderAop();
    }
}

package com.spring.study.bean.aop.perform;

import com.spring.study.aop.perform.PerformConfig;
import com.spring.study.aop.perform.Performance;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PerformConfig.class)
public class PerformTest {
    @Autowired
    private Performance performance;
    @Test
    public void testPerform(){
        performance.perform();
    }

    @Test
    public void testArg(){
        performance.performOrder(2);
    }
}

引入新方法

package com.spring.study.aop.perform;

public interface NewAction {
    void action();
}

package com.spring.study.aop.perform;

import org.springframework.stereotype.Component;

@Component
public class NewActionImpl implements NewAction {
    @Override
    public void action() {
        System.out.println("new performance...");
    }
}

package com.spring.study.aop.perform;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class NewActionIntroducer {
    //performance+表示在performance的子类型下引入
    @DeclareParents(value = "com.spring.study.aop.perform.Performance+",
    defaultImpl = NewActionImpl.class)
    public static NewAction newAction;
}

补充配置类与测试类

package com.spring.study.aop.perform;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class PerformConfig {
    @Bean
    public Audience audience() {
        return new Audience();
    }

    @Bean
    public OderAop oderAop() {
        return new OderAop();
    }

    @Bean
    public NewActionIntroducer newActionIntroducer() {
        return new NewActionIntroducer();
    }
}

package com.spring.study.bean.aop.perform;

import com.spring.study.aop.perform.NewAction;
import com.spring.study.aop.perform.PerformConfig;
import com.spring.study.aop.perform.Performance;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PerformConfig.class)
public class PerformTest {
    @Autowired
    private Performance performance;
    @Autowired
    @Qualifier("startPerform")
    private NewAction newAction;
    @Test
    public void testPerform(){
        performance.perform();
        //通过aop引入新方法
        newAction.action();
    }

    @Test
    public void testArg(){
        performance.performOrder(2);
    }
}

4.XML无注解形式

// TODO

注入一个切面

// TODO
posted @ 2020-07-28 21:27  Dave-Mo  阅读(70)  评论(0)    收藏  举报