上一篇文章我们主要讲了一点关于AOP编程,它的动态考虑程序的运行过程,和Spring中AOP的应用,前置通知,后置通知,环绕通知和异常通知,这些都是Spring中AOP最简单的用法,也是最常用的东西,本节我们 要讲:对上节课的补充和AOP的高级使用,本文将以以下的顺序来进行分析:

  • 无接口的CGLIB动态代理
  • 有接口的CGLIB动态代理
  • 方法名匹配切入点顾问
  • 正则表达式方法切入点顾问
  • 自动代理生成器

(一)无接口的CGLIB动态代理

上一节我们示范的通知(前置,后置...),都有实现接口,我们在动态代理中也曾经强调过jdk的动态代理只能实现有接口的主业务方法,因为动态代理生成的代理类都会实现Proxy从而会放弃继承实现类的父类,所以jdk的动态代理只能够实现有接口的方法类。

我们这里就不对CGLIB多做介绍,后面我会为CGLIB再进行探讨。

言归正传,无接口的通知怎么实现,其实和上一节我们讲的一样,我们按同样的方式配置就好,Spring会自动识别我们实现的方法是否实现了接口,从而动态的来选择实现方法,当然,如果实现的是有接口的方法,Spring在默认情况下回优先使用jdk的动态代理(CGLIB已经停止维护好长时间)。

(二)有接口的CGLIB动态代理

既然Spring对那些实现接口的目标类会优先使用jdk的动态代理来实现AOP,那么我们怎么样才能让Spring使用CGLIB来代现有接口的目标类,

我们就以上一节的后置通知为例(代码就不再展示,在08中有):

我们只需要在配置文件中增加一些配置即可:

//这个是后置通知的原配置文件
<bean id="service" class="com.test.afterMethodAdvice.SomeServiceImp"/> <bean id="myAdvice" class="com.test.afterMethodAdvice.myAfterMethodAdvice"/> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetName" value="service"/>
<!-- <property name="target" value="service"/> -->
<property name="interceptorNames" value="myAdvice"/>
<!---我们只需在这里加上一些配置即可实现->
</bean>

加上这样的配置:

<property name="proxyTargetClass" value="true"/>
<!--proxyTargetClass是org.springframework.aop.framework.ProxyFactoryBean的一个属性,表明是否代理目标实现类,用来控制是否使用CGLIB-->
<!--同样是ProxyFactoryBean的一个属性,表明是否优化-->
<property name="optimize" value="true"/>

(三)方法名匹配切入点顾问

这个名字听上去不知道是什么对吧?在讲这个之前我们先说一下什么是顾问:

顾问:

顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器

在前面我们AOP的实现中,我们只能够通过通知,对一个类的所有方法进行加强,但是不能够选择性的对一个目标对象的个别方法进行加强,所以Spring提供了顾问这个概念,你可以将通知当做顾问的一个组成部分。

下面我们就来看看怎么实现顾问,首先是方法名匹配切入点顾问(下面的实例是在后置通知的基础上进行的增强),指定对应的方法名(简单方法名)来实现加强:

//目标接口
public interface SomeServices {
void doFirst();
void doSecond();
void doThird();
}

//目标实现类
public class SomeServiceImp implements SomeServices{ @Override
public void doFirst() {
System.out.println("print first");
} @Override
public void doSecond() {
System.out.println("print second"); } @Override
public void doThird() {
System.out.println("print third"); } }

//通知类
public class myAfterMethodAdvice implements AfterReturningAdvice { //returnValue:业务方法的返回值
//method:业务方法属性类
//args:方法参数
//target:目标类
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行业务后方法");
}
}

配置文件:

<!--注册目标类  -->
<bean id="service" class="com.test.NameMatchedAdvisor.SomeServiceImp"/>
<!-- 注册后置通知 -->
<bean id="myAdvice" class="com.test.NameMatchedAdvisor.myAfterMethodAdvice"/> <!-- 注册顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 将通知放到顾问中 -->
<property name="advice" ref="myAdvice"/>
<!-- 选定加强的方法 -->
<!-- <property name="mappedName" value="doFirst"/> -->
<!-- 加强多个方法 -->
<!-- <property name="mappedNames" value="doFirst,doSecond"/> -->
<!-- 使用通配符,来指定加强含有ir的方法 -->
<property name="mappedNames" value="*ir*"></property>
</bean> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetName" value="service"/>
<!-- <property name="target" value="service"/> -->
<property name="interceptorNames" value="myAdvisor"/><!--这里要放入顾问-->
</bean>

//测试类
public class test { @Test
public void Test01() {
String source = "com/test/NameMatchedAdvisor/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(source);
SomeServices service = (SomeServices)ac.getBean("ProxyService");
service.doFirst();
service.doSecond();
service.doThird();
}
}

控制台输出:

print first
执行业务后方法
print second
print third
执行业务后方法
//我们会发现只有第一个和第三个方法执行了增强(后置通知)

(四)正则表达式方法切入点顾问

正则匹配切入点顾问,和命名匹配切入点对象相同,只是这里不是用方法名指定,而是用正则表达式指定,并且指定的是全限定方法名(带包名)配置文件上有一点小差异,其他不变。

这里我们只给出配置文件:

	<!--注册目标类  -->
<bean id="service" class="com.test.RegexMatchedAdvisor.SomeServiceImp"/> <!-- 注册后置通知 -->
<bean id="myAdvice" class="com.test.RegexMatchedAdvisor.myAfterMethodAdvice"/> <!-- 注册顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="myAdvice"></property>
<property name="pattern" value=".*doFirst"></property><!-- 这里方法的全限定方法名 -->
</bean> <bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetName" value="service"/>
<!-- <property name="target" value="service"/> -->
<property name="interceptorNames" value="myAdvisor"/>
</bean>

(五)自动代理生成器

上面我们只配置了一个目标类,当我们需要创建多个目标类的时候,那么我们岂不是要配置多个代理工厂bean,这样势必会使得我们的代码臃肿,不利于我们项目的维护,所以Spring提供了自动代理生成器,它会根据需要自动为我们实现代理bean的功能,但是使用这个自动生成代理需要必须是顾问,即不能是通知!

我们来看看怎么配置:


<!--注册目标类 -->
<bean id="service" class="com.test.AutoProxyCreator.SomeServiceImp"/> <!-- 注册后置通知 -->
<bean id="myAdvice" class="com.test.AutoProxyCreator.myAfterMethodAdvice"/>
<!-- 注册顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 将通知放到顾问中 -->
<property name="advice" ref="myAdvice"/>
<!-- 选定加强的方法 -->
<!-- <property name="mappedName" value="doFirst"/> -->
<!-- 加强多个方法 -->
<!-- <property name="mappedNames" value="doFirst,doSecond"/> -->
<!-- 使用通配符,来指定加强含有ir的方法 -->
<property name="mappedNames" value="*ir*"></property>
</bean> <!---下面的配置进行自动代理-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

我们在测试的时候也不需要获取代理类的bean了,可以直接:

SomeServices service = (SomeServices)ac.getBean("service");

直接获取我们目标实现类注册的bean就好了!

这个自动代理我们如果看它的源码的话,我们会发现它实现了BeanPostProcessor接口,熟悉不?对!就是我们的bean前处理和bean后处理,Spring通过它实现了对我们原来目标类的代理(本人才疏学浅就不带大家看源码了)。

但是还有一个问题,刚才我们说了,这个自动代理生成器默认的将所有的bean全代理了固然方便,但是并不是所有的对象都需要代理啊,我怎么选择性的进行代理嘞?

和配置普通bean一样,我们同样可以配置它的属性来完成对目标类的选择性代理!


<!--注册目标类 -->
<bean id="service" class="com.test.BeanNameAutoProxyCreator.SomeServiceImp"/>
<bean id="service2" class="com.test.BeanNameAutoProxyCreator.SomeServiceImp"/> <!-- 注册后置通知 -->
<bean id="myAdvice" class="com.test.BeanNameAutoProxyCreator.myAfterMethodAdvice"/>
<!-- 注册顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 将通知放到顾问中 -->
<property name="advice" ref="myAdvice"/>
<!-- 选定加强的方法 -->
<!-- <property name="mappedName" value="doFirst"/> -->
<!-- 加强多个方法 -->
<!-- <property name="mappedNames" value="doFirst,doSecond"/> -->
<!-- 使用通配符,来指定加强含有ir的方法 -->
<property name="mappedNames" value="doFirst"></property>
</bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="service"></property>
<property name="interceptorNames" value="myAdvisor"></property>
</bean>

注意:和默认自动代理的区别:

class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

这样就可以选择性的代理目标对象了!

至此我们的Spring对AOP的实现就讲完了(关于AspectJ对AOP的实现我们下一节讲),博主整理的这些配置供以后自己查阅,也供大家参考,如有不准确或者错误,不吝赐教!

09 Spring框架 AOP (二) 高级用法的更多相关文章

  1. spring框架 AOP核心详解

    AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...

  2. 跟着刚哥学习Spring框架--AOP(五)

    AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...

  3. sqlalchemy(二)高级用法

    sqlalchemy(二)高级用法 本文将介绍sqlalchemy的高级用法. 外键以及relationship 首先创建数据库,在这里一个user对应多个address,因此需要在address上增 ...

  4. spring框架aop用注解形式注入Aspect切面无效的问题解决

    由于到最后我的项目还是有个邪门的错没解决,所以先把文章大概内容告知: 1.spring框架aop注解扫描默认是关闭的,得手动开启. 2.关于Con't call commit when autocom ...

  5. 08 Spring框架 AOP (一)

    首先我们先来介绍一下AOP: AOP(Aspect Orient Programming),面向切面编程,是面向对象编程OOP的一种补充.面向对象编程是从静态角度考虑程序的结构,面向切面编程是从动态的 ...

  6. Spring框架-AOP详细学习[转载]

    参考博客:https://blog.csdn.net/qq_22583741/article/details/79589910#4-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85% ...

  7. 10 Spring框架 AOP (三) Spring对AspectJ的整合

    上两节我们讲了Spring对AOP的实现,但是在我们的开发中我们不太使用Spring自身的对AOP的实现,而是使用AspectJ,AspectJ是一个面向切面的框架,它扩展了Java语言.Aspect ...

  8. 深入学习Spring框架(二)- 注解配置

    1.为什么要学习Spring的注解配置? 基于注解配置的方式也已经逐渐代替xml.所以我们必须要掌握使用注解的方式配置Spring. 关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯 ...

  9. Spring框架——AOP代理

    我们知道AOP代理指的就是设计模式中的代理模式.一种是静态代理,高效,但是代码量偏大:另一种就是动态代理,动态代理又分为SDK下的动态代理,还有CGLIB的动态代理.Spring AOP说是实现了AO ...

随机推荐

  1. Text类型的字段进行数据替换

    一.text不大于8000 varchar和nvarchar类型是支持replace函数的,所以如果你的text不超过8000,可以先转换成前面两种类型再使用replace. UPDATE News ...

  2. 详略。。设计模式2——单例变形(多例).。。。studying

    ★ 缓存在单例中的使用("单例+缓存"技术) 缓存在编程中使用非常频繁,有着非常关键的数据,它可以帮助程序实现以空间换取时间, 通常被设计成整个应用程序所共享的一个空间,现要求实现 ...

  3. 【Raspberry Pi】DHT11 温度湿度传感器数据读取

    时序图参考厂家说明书:DHT11数字湿温度传感器的原理和应用范例 四个阵脚连接:VCC接3.3伏电源,Dout接GPIO口,我接的是物理12针脚,NC留空,GND接地. 波折1:电阻被错接进了VCC, ...

  4. asp.net session丢失的解决方法小结

    现在我就把原因和解决办法写出来. ASP.NET Session丢失原因: 由于Asp.net程序是默认配置,所以Web.Config文件中关于Session的设定如下: < sessionSt ...

  5. SmartStoreNet解图

    概述: Ioc: Autofac 1. 通过继承, 对MVC的Controller的加强.

  6. iOS App 审核被拒的原因搜罗

    本文转载至 http://ju.outofmemory.cn/entry/108500   iOS app 审核 1.程序有重大bug,程序不能启动,或者中途退出. 2.绕过苹果的付费渠道,我们之前游 ...

  7. 56、LeakCanary——直白的展现Android中的内存泄露

    转载:http://blog.csdn.net/watermusicyes/article/details/46333925 DEMO下载地址:https://github.com/SOFTPOWER ...

  8. python的猴子补丁monkey patch

    monkey patch指的是在运行时动态替换,一般是在startup的时候. 用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/ ...

  9. tornado详细介绍

    Tornado Web服务器概览,tornado教程,tornado开发教程 概览 漏洞 | 漏洞目录 | 安全文档 Overview 下载和安装 模块索引 主要模块 底层模块 Tornado 攻略 ...

  10. cxGrid 根据列值变色(样式)

    在使用cxGrid的过程中,某一个单元格经常需要根据其他单元格的值来做相应的变色,如: 在cxGridDBTableView中,选定要变样式(如背景色.字体属性等)的列, 打开事件Events -&g ...