您的位置:首页 > 编程语言 > Java开发

Spring AOP动态代理-切面

2016-06-02 14:14 1346 查看

在上一节中,我们通过Advice可以对目标类进行增强,使得目标类在调用的时候可以执行增强类中的代码,但是,增强类适配了目标类中的所有方法。如果我们只需要对目标类中的部分方法使用增强类,该如何操作呢?比如我们上一节的场景:乘客乘坐火车,在上车之前需要检票,在这一节中我们继续添加一项业务:旅客服务。 相关代码:

public interface TakingTrain {
public void takeTrain(String name) throws RestException;
public void customSerive(String name);
}
//接口的实现
public void customSerive(String name) {
System.out.println("Hi, "+name+" ,may i help you?");
}

修改我们的测试类代码: 添加:proxy.customSerive("LaoWang");

@Test
public void testAdivice(){
ProxyFactory factory = new ProxyFactory();
TakingTrain trainImpl  = new TakingTrainImpl();
factory.setInterfaces(trainImpl.getClass().getInterfaces());
factory.setTarget(trainImpl);
factory.addAdvice(new CheckTicketAdvice());
TakingTrain proxy = (TakingTrain) factory.getProxy();
try {
proxy.takeTrain("LaoWang");
proxy.customSerive("LaoWang");
} catch (RestException e) {

}
}

打印结果:

please show your tickes
Hi LaoWang Welcome to take the train
please show your tickes
Hi, LaoWang ,may i help you?

这个时候我们发现 please show your tickes这句话打印了两遍。也就是说CheckTicketAdvice中的方法执行了两遍。这可不是我们想要的结果。 而我们现在需要的是对TakingTrain 中的 takeTrain 方法之前调用。而不是所有的方法都调用。 用什么方法可以实现这个功能呢?AOP!它可以通过切面讲增强类有选择的织入到目标类的特定方法中。 换句话说,我们需要两个功能:

  • 拦截类:ClassFilter

  • 拦截方法:MethodMatcher

相关的类图

具体实现(使用静态方法匹配切面):

1.定义切面,在切面内可进行类级别和方法级别的拦截。 注意,将切点设置到切面内:

public class StaticMethodCheckTicketAdvisor extends StaticMethodMatcherPointcutAdvisor{

public StaticMethodCheckTicketAdvisor(Advice advice) {
this.setAdvice(advice);
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
return "takeTrain".equals(method.getName());
}
}

2.切点保持不变:

public class CheckTicketAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("please show your tickes");
}
}

3.实现类:

@Test
public void testStaticMethodAdvisor(){
ProxyFactory factory = new ProxyFactory();
StaticMethodCheckTicketAdvisor advisor = new StaticMethodCheckTicketAdvisor(new CheckTicketAdvice());
TakingTrain trainImpl  = new TakingTrainImpl();
factory.setInterfaces(trainImpl.getClass().getInterfaces());
factory.setTarget(trainImpl);
factory.addAdvisor(advisor);
TakingTrain proxy = (TakingTrain) factory.getProxy();
try {
proxy.takeTrain("LaoWang");
proxy.customSerive("LaoWang");
} catch (RestException e) {

}
}

4.打印结果:

please show your tickes
Hi LaoWang Welcome to take the train
Hi, LaoWang ,may i help you?

具体实现(使用表达式匹配切面):

1.定义切面,在切面内可进行类级别和方法级别的拦截。 注意,将切点,以及表达式设置到切面内:

public class RegexpMethodCheckTicketAdvisor extends RegexpMethodPointcutAdvisor{

public RegexpMethodCheckTicketAdvisor() {
super();
// TODO Auto-generated constructor stub
}
public RegexpMethodCheckTicketAdvisor(Advice advice) {
super(advice);
// TODO Auto-generated constructor stub
}
public RegexpMethodCheckTicketAdvisor(String pattern, Advice advice) {
super(pattern, advice);
// TODO Auto-generated constructor stub
}
public RegexpMethodCheckTicketAdvisor(String[] patterns, Advice advice) {
super(patterns, advice);
// TODO Auto-generated constructor stub
}
}

2.切点保持不变:

public class CheckTicketAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("please show your tickes");
}
}

3.实现类:

@Test
public void testRegexpMethodAdvisor(){
ProxyFactory factory = new ProxyFactory();
RegexpMethodCheckTicketAdvisor advisor = new RegexpMethodCheckTicketAdvisor();
advisor.setPattern(".*takeTrain.*");
advisor.setAdvice(new CheckTicketAdvice());
TakingTrain trainImpl  = new TakingTrainImpl();
factory.setInterfaces(trainImpl.getClass().getInterfaces());
factory.setTarget(trainImpl);
factory.addAdvisor(advisor);
TakingTrain proxy = (TakingTrain) factory.getProxy();
try {
proxy.takeTrain("LaoWang");
proxy.customSerive("LaoWang");
} catch (RestException e) {

}
}

4.打印结果:

please show your tickes
Hi LaoWang Welcome to take the train
Hi, LaoWang ,may i help you?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息