发表于: 2017-12-07 23:18:42

1 818


今日完成的事情:

今天讲小课堂:

面向切面编程:

使用基于正则表达式的SpringAOP切面类:

这里使用springAOP的切面类RegexpMethodPointcutAdvisor来配置切面,并在GreetingImpl类中增加两个都以“good”开头的方法,下面要做的就是拦截两个新增方法,而对sayHello()不拦截。

@Service
public class GreetingImpl implements Greeting {
@Override
   public void sayHello(String name) {
System.out.println("Hello:"+name);
   }
//基于正则表达式的Spring AOP切面类
   public void goodMorning(String name){
System.out.println("Good morning!"+name);
   }
public void goodNight(String name){
System.out.println("Good Night!"+name);
   }
}

spring配置文件:

<!-- 基于正则表达式的SpringAOP切面类 -->
<bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
   <property name="advice" ref="greetAroundAdvice"/>
   <property name="pattern" value="com.mmy.serviceImpl.GreetingImpl.good.*"/>
</bean>
<bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="interfaces" value="com.mmy.service.Love"/>
   <property name="target" ref="greetingImpl"/>
   <property name="interceptorNames" value="greetingAdvisor"/>
   <property name="proxyTargetClass" value="true"/> <!-- 代理目标类 -->
</bean>

pattern只匹配以“good”开头的方法:

@Test
public void client4(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
   GreetingImpl greeting= (GreetingImpl) context.getBean("greetingProxy");
   greeting.goodMorning("jack");
   greeting.sayHello("jack");
}

测试结果:

只针对“good”开头的方法进行了增强。

AOP自动代理:

<!-- AOP自动代理 -->
<bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
   <property name="advice" ref="greetAroundAdvice"/>
   <property name="pattern" value="com.mmy.serviceImpl.GreetingImpl.good.*"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
   <property name="optimize" value="true"/>
</bean>

 属性optimize意思是对代理生成策略是否优化,true表示如果目标类有接口则代理接口(JDK动态代理),如果没有则代理类(CGLib动态代理),这样便可以取代前面强制代理类的proxyTargetClass属性。

测试类:

@Test
public void client5(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
   GreetingImpl greeting= (GreetingImpl) context.getBean("greetingImpl");
   greeting.goodMorning("jack");
   greeting.sayHello("jack");
}

此时因为是自动代理,getBean()中的值不再是原来代理id(greetingProxy),而是目标类GreetingImpl的Bean的id(greetingImpl),他同样也是一个代理对象。

AspectJ execution 表达式拦截:

@Aspect
@Component
public class AroundAspect {
@Around(value = "execution(* com.mmy.serviceImpl.GreetingImpl.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
before();
       Object result=pjp.proceed();
       after();
       return result;
   }

public void before(){
System.out.println("Before");
   }

public void after(){
System.out.println("After");
   }

spring配置文件:

<context:component-scan base-package="com.mmy.*"/>
<!-- AspectJ execution 表达式拦截 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

这样两行配置,节约了配置大量代理和切面的时间,proxy-target-class为true表示代理目标类。

之前的切点表达式定义了拦截类中所有方法,所以每个方法都被增强。同时在ApplicationContext中获取的greetingImpl代理对象,可转型为自己静态实现的接口Greeting也可以是实现类GreetingImpl。属性proxy-target-class默认为false,代表只代理接口,也就是说只能将代理转型为Greeting,而不能是GreetingImpl。

测试类:

@Test
public void client5(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
   GreetingImpl greeting= (GreetingImpl) context.getBean("greetingImpl");
   greeting.goodMorning("jack");
   greeting.sayHello("jack");
}

 AspectJ @DeclareParents 注解(引入增强):

定义一个切面类AroundAspect:value属性指定了哪种类型的bean要引入该接口。defaultImpl属性指定了为引入功能提供实现的类,@DeclareParents注解所标注的属性指明要引入的接口。

//引入增强
@DeclareParents(value = "com.mmy.serviceImpl.GreetingImpl",defaultImpl = LoveImpl.class)
private Love love;

LoveImpl实现类:将这个实现类引入目标类GreetingImpl中,就能使用display方法。

public class LoveImpl implements Love{
@Override
   public void display(String name) {
System.out.println("I Love You:"+name);
   }
}

在ApplicationContext中获取的greetingImpl对象是个代理对象,可转型为自己静态实现的接口Greeting,也可以转型为自己动态实现的接口Love,可随意切换。现在的AspectJ的引入增强跟上面的SpringAOP的引入增强只能面向实现类相比,还可面向接口编程。

@Test
public void client6(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
   GreetingImpl greeting= (GreetingImpl) context.getBean("greetingImpl");
   greeting.sayHello("jack");
   Love love=(Love)greeting;
   love.display("jack");
}

运行结果:

就把类作为增强织入greetingImpl。

在XML中声明切面:

 在Spring中,注解和自动代理提供了一种很方便的方式来创建切面,但是面向注解的切面有一个明显的劣势:你必须能够为通知类添加注解,为了这一点,必须要有源码。如果你没有源码的话,或者不想将AspectJ注解放到你的代码之中,Spring提供了另外一种方法,Spring XML 配置文件中声明切面。

  将前面实现类GreetingImpl和切面类AroundAspect的相关注解@Component,@Aspect,@Around全都移除。编辑XML:

<bean id="aroundAspect" class="com.mmy.aop.AroundAspect"/>
<bean id="greetingImpl" class="com.mmy.serviceImpl.GreetingImpl"/>
<aop:config>
   <aop:aspect ref="aroundAspect">
       <aop:around method="around" pointcut="execution(* com.mmy.serviceImpl.GreetingImpl.*(..))"/>
   </aop:aspect>
</aop:config>

我们发现原来的两条配置都可以删除,但是要注意,没有显式配置<aop:aspectj-autoproxy/>不代表不使用自动代理,这条配置默认属性为“false”,表示只代理接口(JDK动态代理),所以如果只想代理接口,可以不用显式写出。

如果想要使用CGLib动态代理,则增加:

<aop:aspectj-autoproxy proxy-target-class="true"/>

这时又可以代理目标类了:

public void client7(){
ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");
   Greeting greeting= (GreetingImpl) context.getBean("greetingImpl");
   greeting.sayHello("jack");
}

明日计划的事情:

以后每天都要看一下敏捷开发流程,还要明天看一下方案怎么写。

遇到的问题:

收获:

学习了Spring AOP从java代理,到spring集成。



返回列表 返回列表
评论

    分享到