发表于: 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集成。
评论