code前行

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理

因为Spring 基于动态代理,所以Spring 只支持 方法连接点。其他如 AspectJ 和 JBoss 可以提供更细粒度的连接点

 而且对于static方法和final方法都无法支持aop(因为此类方法无法生成代理类)

首先看下 XML 方式来使用 Spring AOP 切面

先定义一个接口   (切点)

public interface Performance {
    public void perform();
}

一个实现类

public class PerformanceImpl implements Performance {
    @Override
    public void perform() {
        System.out.println("正在演出...");
    }
}

增强类  (切面  )

public class Audience {
    public void performance() {}
    public void closePhones() {
        System.out.println("关闭手机");
    }
    public void look() {
        System.out.println("看表演");
    }
    public void openPhones() {
        System.out.println("打开手机");
    }
    public void goHome() {
        System.out.println("回家");
    }
    public void doSomething() {
        System.out.println("鼓励");
    }

//这个是环绕通知,带有ProceedingJoinPoint参数 public void watchPerformance(ProceedingJoinPoint jp) { try { System.out.println("观看前"); jp.proceed();//该方法调用被代理对象的目标方法 System.out.println("观看后"); } catch (Throwable e) { e.printStackTrace(); } } }

XML文件中配置

<bean id="performance" class="springAop.PerformanceImpl"/>
        <bean id="audience" class="springAop.Audience"/>
        
        <aop:config>
            <!-- 切面:提供方法的类 -->
            <aop:aspect id="watch" ref="audience">
            <!-- 切点: 将要被增强的类的方法-->
                <aop:pointcut id="addAllMethod" expression="execution(* springAop.Performance.perform(..))" />
                <aop:before method="closePhones" pointcut-ref="addAllMethod" />
                <aop:after method="openPhones" pointcut-ref="addAllMethod" />

                 <!-- 声明环绕通知 -->
                 <aop:after method="watchPerformance" pointcut-ref="addAllMethod" />

            </aop:aspect>
        </aop:config>

测试

public class XmlTest {
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext ctx =  new ClassPathXmlApplicationContext("aop.xml");
        Performance performance = ctx.getBean("performance", Performance.class);
        performance.perform();
    }
}

 

注解方式

增强类的注解方式

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class Audience {
    
    @Pointcut("execution(** springAop.Performance.perform(..))")
    public void performance() {}
    
    //通知方法会在目标方法调用前执行
    @Before("execution(** springAop.Performance.perform(..))")
    public void closePhones() {
        System.out.println("关闭手机");
    }
    //@Before("performance()")
    public void look() {
        System.out.println("看表演");
    }
    //通知方法会在目标方法返回后调用
    @AfterReturning("execution(** springAop.Performance.perform(..))")
    public void openPhones() {
        System.out.println("打开手机");
    }
    //通知方法会在目标方法返回或抛出异常后调用
    @After("execution(** springAop.Performance.perform(..))")
    public void goHome() {
        System.out.println("回家");
    }
    //通知方法会在目标方法抛出异常后调用
    @AfterThrowing("execution(** springAop.Performance.perform(..))")
    public void doSomething() {
        System.out.println("鼓励");
    }
    //环绕通知
    @Around("execution(** springAop.Performance.perform(..))")
    public void watchPerformance(ProceedingJoinPoint jp) {
        
        try {
            System.out.println("观看前");
            jp.proceed();//该方法调用被代理对象的目标方法
            System.out.println("观看后");
        } catch (Throwable e) {
            e.printStackTrace();
        }
        
    }
}

添加一个配置类

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  //声明为配置管理类
@EnableAspectJAutoProxy   //启用AspectJ自动代理
@ComponentScan   //启用组件扫描
/**
 * 默认情况下@ComponentScan会扫描与配置类相同的包  
 * 可以@ComponentScan("包名")这样指定要扫描的路径
 * 也可以指定多个扫描包名@ComponentScan(basePackages={"packagesName1","packagesName2"})
 * 
 * XML配置方式  <context:component-scan>
 */
public class ConcertConfig {

    @Bean  //声明 Audience bean
    public Audience audience() {
        return new Audience();
    }
    
    @Bean
    public Performance performance() {
        return new PerformanceImpl();
    }
}

测试代码

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=ConcertConfig.class)
public class JavaConfigTest {
  
    @Autowired
    private Performance performance;
    
    @Test
    public void testAop() {
        performance.perform();
    }
}

 处理带参数的通知

一下代码为在注解方式基础上改动而来

接口类

public interface Performance {
    public void perform();
    
    public void haveParam(int i);
}
Audience 类中
@Pointcut("execution(** springAop.Performance.haveParam(int)) && args(param)")
    public void performance(int param) {}

 @Before("performance(param)")
    public void look(int param) {
        System.out.println("测试参数" + param);
    }

测试代码

    @Test
    public void testAop() {
        performance.haveParam(6);
    }

通过注解引入新功能

首先我们定义一个新接口

public interface Encoreable {
    void performEncore();
}

该接口实现类

public class EncoreableImpl implements Encoreable {

    @Override
    public void performEncore() {
        System.out.println("Encoreable引入了新功能.....");
    }

}

将 performEncore 功能引入 Performance 的实现类中

配置类

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;

@Aspect
public class EncoreableAspect {
    /**
     * value 属性指定了那种类型的Bean要引入该接口,(这里既所有实现了Performance的类型)。标记后面的加号表示是 Performance的所有子类,而不是Performance本身
     * defaultImpl 属性指定了为引入功能提供具体实现的类。
     * @DeclareParents 注解所标注的静态属性指明了要引入的接口 (这里是 Encoreable 接口)
     */
    @DeclareParents(value = "springAop.Performance+", defaultImpl = EncoreableImpl.class)
    public static Encoreable encoreable;
}

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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
        
        <!-- 启用AspectJ自动代理 -->
        <aop:aspectj-autoproxy />
        <bean id="performance" class="springAop.PerformanceImpl"/>
        <bean id="audience" class="springAop.Audience"/>
        <bean id="encoreableAspect" class="springAop.EncoreableAspect"/>
        <bean id="encoreable" class="springAop.EncoreableImpl"/>
          
</beans>

测试类

public class XmlTest {

    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext ctx =  new ClassPathXmlApplicationContext("aop.xml");
        Performance performance = ctx.getBean("performance", Performance.class);
        performance.perform();
        Encoreable performance1 = ctx.getBean("performance", Encoreable.class);
        performance1.performEncore();
    }
}

输出结果:

正在演出...
Encoreable引入了新功能.....

关于增强方式:https://www.cnblogs.com/zhaozihan/p/5953063.html

posted on 2018-03-11 22:26  code前行  阅读(165)  评论(0编辑  收藏  举报