通过切面为Spring bean添加新的方法

背景:

Performance代表任何类型的现场表演,如舞台剧、电影或音乐会。

Audience有四个方法,定义了一个观众在观看演出时可能会做的事情。在演出之前,观众要就坐takeSeats()并将手机调至静音状态silenceCellPhones()。如果演出很精彩的话,观众应该会鼓掌喝彩applause()。不过,如果演出没有达到观众预期的话,观众会要求退款demandRefund()。

加入Encoreable接口,代表此表演有返场演出performEncore()方法。此演出并不是常规的Performance中存在的,属于新的方法。如何在执行perform()之后执行新的方法?

 

Java并不是动态语言。一旦类编译完成了,我们就很难再为该类添加新的功能了。如果切面不仅仅实现了所包装bean相同的接口,而且还实现了新的接口,那么切面所通知的bean看起来似乎也像是实现了新的接口。其实底层实现类并没有真的实现新的接口,当新的接口的方法被调用时,代理会把此调用委托给实现了新接口的某个实现对象,实际上,一个bean的实现被拆分到了多个类中。

需要引入依赖

<!--spring aop依赖AspectJ-->
    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
    </dependency>

 

Performance接口与实现类PerformanceImpl

 

public interface Performance {

    void perform();
}

@Component("performance")
public class PerformanceImpl implements Performance {
    @Override
    public void perform() {
        System.out.println("perform...");

    }
}

 

常规的切面类:Audience类

@Component
@Aspect
public class Audience {

    @Pointcut("execution(* chapter04.performance.Performance.perform(..))")
    public void performance(){}

    @Around("performance()")
    public void watchPerformance(ProceedingJoinPoint jp){
        try {
            System.out.println("Silencing cell phones");
            System.out.println("Taking seats");
            jp.proceed();
            System.out.println("CLAP CLAP CLAP");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Demanding a refund");
        }
    }
}

引入新的接口:Encoreable接口与实现类DefaultEncoreable

public interface Encoreable {

    void performEncore();
}

public class DefaultEncoreable implements Encoreable {
    @Override
    public void performEncore() {
        System.out.println("perform encore...");
    }
}

新引入接口需要的切面类EncoreableIntroducer

/**
 * 通过@DeclareParents注解,将Encoreable接口引入到Performance bean中
 * Created by Administrator on 2017/12/1.
 */
@Component
@Aspect
public class EncoreableIntroducer {
    /**
     * value属性指定了哪种类型的bean要引入该接口,在本例中,也就是所有实现Performance的类型。
     * defaultImpl属性指定了为引入功能提供实现的类
     * @DeclareParents 注解所标注的静态属性指明了要引入了接口。在这里,我们所引入的是Encoreable接口。
     */
    @DeclareParents(value="chapter04.performance.Performance+",defaultImpl = DefaultEncoreable.class)
    public static Encoreable encoreable;

}

applicationContext.xml配置

    <context:component-scan base-package="aop_test,chapter04"/>
	
	<!-- 开启aop注解 -->
    <aop:aspectj-autoproxy/>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class testPerformance {
    @Autowired
    Performance performance;

    @Test
    public void test(){
        performance.perform();
        Encoreable encoreable = (Encoreable) performance;
        encoreable.performEncore();
    }
}

测试结果

Silencing cell phones
Taking seats
perform...
CLAP CLAP CLAP
perform encore...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值