`
p_3er
  • 浏览: 55775 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

第三章 AOP 通过Java API创建切面

 
阅读更多

在前面使用增强的时候,我们发现增强会被织入到目标类的所有的方法中。我们如果把增强织入到目标类的特定的方法中,需要使用切点进行目标连接点的定位。然后我们可以通过切点及增强生成一个切面了。


3.4.1切点类型

静态方法切点:org.springframework.aop.support.StaticMethodMatcherPointcut

动态方法切点:org.springframework.aop.support.DynamicMethodMatcherPointcut

注解切点:org.springframework.aop.support.annotation.AnnotationMatchingPointcut

表达式切点:org.springframework.aop.support.ExpressionPointcut

流程切点:org.springframework.aop.support.ControlFlowPointcut


3.4.2静态方法来匹配切面

org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor


a、增强类

在这里使用的是3.3.2的前置增强:

http://blog.csdn.net/p_3er/article/details/9239925

只是UserDaoImpl中有两个方法,save方法和delete方法。然后我们给save方法配置切面。

b、切面类继承StaticMethodMatcherPointcutAdvisor

public class StaticAdvisor extends StaticMethodMatcherPointcutAdvisor {
	/*
	 * 切点方法匹配规则
	 */
	public boolean matches(Method method, Class<?> clazz) {
		return method.getName().equals("save");
	}

	/*
	 * 重写StaticMethodMatcherPointcut的getClassFilter()
	 * 匹配哪个类下的方法
	 */
	public ClassFilter getClassFilter() {
		ClassFilter classFilter = new ClassFilter() {
			public boolean matches(Class<?> clazz) {
				return UserDaoImpl.class.isAssignableFrom(clazz);
			}
		};
		return classFilter;
	}
}


c、配置

<!-- 增强Bean -->
	<bean id="userDaoBeforeAdvice" class="cn.framelife.spring.advice.UserDaoBeforeAdvice"></bean>
	
	<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	<!-- 管理切面类。p:advice-ref把增强放入切面 -->
	<bean id="staticAdvisor" class="cn.framelife.spring.advisor.StaticAdvisor" p:advice-ref="userDaoBeforeAdvice"></bean>
	
	<!-- 
		设置父代理类 
		p:interceptorNames 放切面,而不再是增强
	-->
	<bean id="paramProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="staticAdvisor"
		p:proxyTargetClass="true" />	
	<!-- 设置子代理类 -->
	<bean id="userDaoProxy" parent="paramProxy" p:target-ref="userDao"></bean>

d、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserDao userDao = (UserDao) context.getBean("userDaoProxy");
		//UserDaoImpl中有两个方法,save方法中有切面,delete中没切面
		userDao.save();
		System.out.println("----------");
		userDao.delete();

e、结果

我是前置增强:save
保存用户...
----------
删除用户...



3.4.3静态正则表达式方法配置切面

这种方法不需要自己写切面类。

org.springframework.aop.support.RegexpMethodPointcutAdvisor是正则表达式方法匹配的切面实现类。


a、增强类

在这里使用的是3.3.2的前置增强:

http://blog.csdn.net/p_3er/article/details/9239925


b、配置

<!-- 增强Bean -->
	<bean id="userDaoBeforeAdvice" class="cn.framelife.spring.advice.UserDaoBeforeAdvice"></bean>
	
	<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	<!-- 
		设置切面Bean 
		patterns 用正则表达式定义目标类全限定方法名的匹配模式串
			目标类全限定方法名,指的是带类名的方法名。如: cn.framelife.spring.dao.impl.UserDaoImpl.delete()
		<value>.*delete</value> 匹配模式串
	-->
	<bean id="regexpAdvisor" 
		class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
		p:advice-ref="userDaoBeforeAdvice">
		<property name="patterns">
			<list>
				<value>.*delete</value>
			</list>
		</property>
	</bean>
	
	<!-- 
		设置代理类 
	-->
	<bean id="regexpProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="regexpAdvisor"
		p:target-ref="userDao"
		p:proxyTargetClass="true" />	

c、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserDao userDao = (UserDao) context.getBean("regexpProxy");
		userDao.save();
		System.out.println("----------");
		userDao.delete();


d、结果

保存用户...
----------
我是前置增强:delete
删除用户...


常用的正则表达式规则

1.*set.*表示所有类中的以set为前缀的方法。如:com.abc.UserDao.setName()

2com\.abc\.service\..*表示com.abc.service.包下所有的类的所有的方法。

Com.abc.service.a.User.setName()

Com.abc.service.UserService.save()

3com\.abc\.service\..*Service\..*表示com.abc.service包下以Service结尾的类的所有的方法。如:com.abc.service.UserService.save()

4com\.abc\.service\..*Service\.save.+匹配所有以save为前缀的方法,而且save后必须拥有一个或多个字符。如:com.abc.service.UserService.saveUser()



3.4.4动态切面

org.springframework.aop.support.DynamicMethodMatcherPointcut类即有静态切点检查的方法,也有动态切点检查的方法。由于动态切点检查会对性能造成很大的影响,我们应当避免在运行时每次都对目标类的各个方法进行检查。

Spring检查动态切点的机制:在创建代理时对目标类的每个连接点进行静态切点检查,如果仅静态切点检查就可以知道连接点是不匹配的,在运行期就不进行动态检查了;如果静态切点检查是匹配的,在运行期才进行动态方法检查。

动态切面通过DefaultPointcutAdvisor切面类与DynamicMethodMatcherPointcut切点结合起来生成。主要是针对连接点方法的参数。

a、增强类

在这里使用的是3.3.2的前置增强:

http://blog.csdn.net/p_3er/article/details/9239925

只是UserDaoImpl中多了一个out方法,带一个参数。


b、切点类继承DynamicMethodMatcherPointcut

public class DynamicPointcut extends DynamicMethodMatcherPointcut {
	//用list集合保存参数名
	private List<String> specialNames = new ArrayList<String>();
	
	public DynamicPointcut(){
		specialNames.add("aa");
		specialNames.add("bb");
	}
	/*
	 * 对类进行静态切点检查
	 */
	public ClassFilter getClassFilter() {
		
		return new ClassFilter() {
			@Override
			public boolean matches(Class<?> targetClass) {
				System.out.println("使用getClassFilter静态检查:"+targetClass.getName());
				return UserDaoImpl.class.isAssignableFrom(targetClass);
			}
		};
	}

	/*
	 *对方法进行静态切点检查
	 */
	public boolean matches(Method method, Class<?> targetClass) {
		System.out.println("使用matches(method,targetClass)方法静态检查:"+targetClass.getName()+"--"+method.getName());
		return method.getName().equals("out");
	}


	/*
	 *对方法进行动态切点检查
	 */
	public boolean matches(Method method, Class<?> targetClass, Object[] args) {
		System.out.println("使用matches(method,targetClass)方法动态检查:"+targetClass.getName()+"--"+method.getName()+"的参数");
		String name = (String)args[0];
		return specialNames.contains(name);
	}
}

c、配置

<!-- 增强Bean -->
	<bean id="userDaoBeforeAdvice" class="cn.framelife.spring.advice.UserDaoBeforeAdvice"></bean>

	<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	
	<!-- 切面 -->
	<bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<!-- 设置切点 -->
		<property name="pointcut">
			<bean class="cn.framelife.spring.pointcut.DynamicPointcut"></bean>
		</property>
		<!-- 织入增强 -->
		<property name="advice" ref="userDaoBeforeAdvice"></property>
	</bean>
	
	<!-- 
		设置代理 
	-->
	<bean id="dynamicProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="dynamicAdvisor"
		p:target-ref="userDao"
		p:proxyTargetClass="true" />	

d、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserDao userDao = (UserDao) context.getBean("dynamicProxy");
		//UserDaoImpl中多了一个out方法,带一个参数。
		System.out.println("----------");
		userDao.save();
		System.out.println("----------");
		userDao.out("aa");
		System.out.println("----------");
		userDao.out("1111");
		System.out.println("----------");


e、结果

使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--out
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--save
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--delete
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--clone
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--toString
----------
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--save
保存用户...
----------
使用getClassFilter静态检查:cn.framelife.spring.dao.impl.UserDaoImpl
使用matches(method,targetClass)方法静态检查:cn.framelife.spring.dao.impl.UserDaoImpl--out
使用matches(method,targetClass)方法动态检查:cn.framelife.spring.dao.impl.UserDaoImpl--out的参数
我是前置增强:out
out输出名字为:aa
----------
使用matches(method,targetClass)方法动态检查:cn.framelife.spring.dao.impl.UserDaoImpl--out的参数
out输出名字为:1111
----------


3.4.5流程切面

一个类中的某一方法使用目标类的两个方法,那么我们可以使用流程切面给这两个方法都积入增强。

如:UserServiceImpl(使用类)operate方法中使用UserDaoImpl(目标类)的两个方法。

流程切面使用ControlFlowPointcutDefaultPointcutAdvisor结合形成。

a、增强类

在这里使用的是3.3.2的前置增强:

http://blog.csdn.net/p_3er/article/details/9239925

只是UserDaoImpl中有两个方法,save方法和delete方法。然后我们给save方法配置切面。


bUserServiceImpl

public class UserServiceImpl implements UserService {
	private UserDao userDao;
	
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	public void addUser() {
		userDao.save();
	}

	@Override
	public void operate() {
		//这里同时使用了userDao的两个方法
		userDao.delete();
		userDao.save();
	}
}

c、配置

<!-- 增强Bean -->
	<bean id="userDaoBeforeAdvice" class="cn.framelife.spring.advice.UserDaoBeforeAdvice"></bean>

	<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	<!-- 切点 -->
	<bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
		<!-- 指定流程切点的类 -->
		<constructor-arg type="java.lang.Class" value="cn.framelife.spring.service.impl.UserServiceImpl"></constructor-arg>
		<!-- 指定流程切点的方法 -->
		<constructor-arg type="java.lang.String" value="operate"></constructor-arg>
	</bean>
	
	<!-- 切面 -->
	<bean id="controlFlowAdvisor" 
		class="org.springframework.aop.support.DefaultPointcutAdvisor"
		p:pointcut-ref="controlFlowPointcut"
		p:advice-ref="userDaoBeforeAdvice"/>	
	
	<!-- 
		设置代理 
	-->
	<bean id="controlFlowProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="controlFlowAdvisor"
		p:target-ref="userDao"
		p:proxyTargetClass="true" />
	
	<!-- 把使用目标类的Bean交由Spring管理 -->
	<bean id="userService" class="cn.framelife.spring.service.impl.UserServiceImpl">
		<property name="userDao" ref="controlFlowProxy"></property>
	</bean>


d、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserService userService = (UserService) context.getBean("userService");
		userService.operate();
		System.out.println("----------------");
		userService.addUser();


e、结果

我是前置增强:delete
删除用户...
我是前置增强:save
保存用户...
----------------
保存用户...


3.4.6复合切面

在前面的例子中,我们所定义的切面都只有一个切点而已。有时候我们一个切面需要多个切点,也就是多个条件才能决定连接点。多个切点组成一个切点,这样的切点是复合切点。由复合切点加上增强形成的切面,称为复合切面。

a、增强类

在这里使用的是3.3.2的前置增强:

http://blog.csdn.net/p_3er/article/details/9239925


b、一个普通类中有一个获取Pointcut的方法

public class MyPointcut {
//获取Pointcut的方法名是get开头
	public Pointcut getMyComposablePointcut(){
		//创建一个复合切点
		ComposablePointcut cp = new ComposablePointcut();

		//创建一个流程切点(参数:使用类、类中的方法)这里使用的是3.4.5中的UserServiceImpl类
		Pointcut pt1 = new ControlFlowPointcut(UserServiceImpl.class,"operate");
		
		//创建一个静态方法切点
		Pointcut pt2 = new StaticMethodMatcherPointcut() {
			public boolean matches(Method method, Class<?> clazz) {
				return UserDaoImpl.class.isAssignableFrom(clazz)&&method.getName().equals("delete");
			}
		};

		//两个切点进行交集操作.
		return cp.intersection(pt1).intersection(pt2);
	}
}

c、配置

<!-- 增强Bean -->
	<bean id="userDaoBeforeAdvice" class="cn.framelife.spring.advice.UserDaoBeforeAdvice"></bean>

	<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	<!-- 切点所在类 -->
	<bean id="myPoincut" class="cn.framelife.spring.pointcut.MyPointcut"></bean>
	
	<!-- 
		切面
		p:pointcut #{ myPoincut.myComposablePointcut} 是由MyPointcut的getMyComposablePointcut方法获取的
	-->
	<bean id="composableAdvisor" 
		class="org.springframework.aop.support.DefaultPointcutAdvisor"
		p:pointcut="#{ myPoincut.myComposablePointcut}"
		p:advice-ref="userDaoBeforeAdvice"/>	
	
	<!-- 
		设置代理 
	-->
	<bean id="composableProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="composableAdvisor"
		p:target-ref="userDao"
		p:proxyTargetClass="true" />
	
	<!-- 把使用目标类的Bean交由Spring管理 -->
	<bean id="userService" class="cn.framelife.spring.service.impl.UserServiceImpl">
		<property name="userDao" ref="composableProxy"></property>
	</bean>


d、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserService userService = (UserService) context.getBean("userService");
		userService.operate();

e、结果

我是前置增强:delete
删除用户...
保存用户...

3.4.7引介切面

a、使用3.3.6引介增强里面的东西(接口与增强类)


b、配置

<!-- 目标Bean -->
	<bean id="userDao" class="cn.framelife.spring.dao.impl.UserDaoImpl"></bean>
	
	<!-- 
		切面
		constructor-arg 设置引介增强
	-->
	<bean id="introductionAdvisor" 
		class="org.springframework.aop.support.DefaultIntroductionAdvisor">
		<constructor-arg>
			<bean class="cn.framelife.spring.advice.IntroductionAdvice"></bean>
		</constructor-arg>
	</bean>	
	
	<!-- 
		设置代理 
	-->
	<bean id="incluctionProxy" 
		class="org.springframework.aop.framework.ProxyFactoryBean"
		p:interceptorNames="introductionAdvisor"
		p:target-ref="userDao"
		p:proxyTargetClass="true" />


c、测试

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		UserDao userDao = (UserDao) context.getBean("aProxy");
		userDao.save();
		
		System.out.println("-------------");
		
		AInterface a = (AInterface)userDao;
		a.say();
		
		System.out.println("-------------");
		userDao.save();


d、结果

方法执行前执行
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation
save
保存用户...
方法执行后执行
-------------
方法执行前执行
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation
say
UserDao要说话
方法执行后执行
-------------
方法执行前执行
org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation
save
保存用户...
方法执行后执行


分享到:
评论

相关推荐

    第三章:Spring AOP API 设计与实现1

    Spring AOP API 设计与实现是Spring框架的重要组成部分,它提供了面向切面编程的能力,使得开发者可以在不修改源代码的情况下,对程序进行横切关注点的处理,如日志记录、事务管理等。本章主要涵盖了Spring AOP的多...

    第3章 Spring AOP.ppt

    Spring AOP,全称为Spring面向切面编程,是Java EE企业级应用开发中的一个重要组成部分。它提供了一种在不改变原有代码的情况下,通过添加额外功能(如日志、事务管理)来增强程序的能力。AOP的主要目标是解决传统...

    java文件上传,断点续传+aop操作日志

    在Java中,通常使用Servlet API或者第三方库如Apache Commons FileUpload来实现。Servlet 3.0及以上版本提供了内置的Part接口支持文件上传,而FileUpload库则提供更灵活的配置和错误处理机制。在处理文件上传时,...

    AOP面向切面编程的JavaScript实现

    面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,旨在将关注点分离,使得系统中的交叉关注点,如日志、事务管理、权限检查等,可以从核心业务逻辑中解耦出来。在Java领域,Spring框架是AOP的典型...

    java编程各类api

    在Java中,API包括了Java核心库(JDK)和许多第三方库。 1. **Java核心API**: - **IO流**:Java.IO包包含了处理输入输出操作的各种类,如InputStream、OutputStream、Reader、Writer等,用于读写文件、网络数据...

    aopalliance.jar包

    AOP联盟(aopalliance)是Java平台上的一个开源项目,提供了一个统一的API,使得不同的AOP框架可以共享相同的切面实现。aopalliance-1.0.jar是这个项目的标准库,包含了一系列基础接口,使得不同的AOP框架如Spring、...

    java api文档jdk-6u30-apidocs

    2. **动态代理增强**:增强了Java反射机制,允许创建动态代理类,方便实现回调和AOP(面向切面编程)。 3. **Scripting API**:允许在Java应用程序中集成脚本语言,如JavaScript、Groovy等。 4. **XML改进**:包括...

    AOP在Android中的使用(作为依赖库)

    在Java领域,Spring框架是AOP应用的典型代表,但在Android开发中,由于原生API并未直接支持AOP,我们需要借助第三方库来实现这一功能。 在Android中,AOP通常用于提升代码的可维护性和可扩展性。通过在不修改原有...

    Jmail+ HttpInvoker+定时任务+Aop+Rmi+

    在Java中,Spring框架提供了强大的AOP支持,通过定义切面、通知类型(前置、后置、异常、环绕等)来实现切面的织入。描述中的例子展示了如何使用AOP进行日志处理,这能帮助开发者更好地跟踪和理解程序运行情况,同时...

    第三章 Spring MVC Servlet API与Json的支持

    在本章中,我们将深入探讨Spring MVC框架与Servlet API以及JSON支持的相关知识。...在实践中,不断探索和学习Spring MVC的高级特性,如AOP(面向切面编程)、拦截器、异常处理等,将有助于提升项目的整体质量。

    java常用API大全1

    这个API文档详细列出了Spring框架的核心组件,如依赖注入、AOP(面向切面编程)、数据访问/集成、Web支持等。通过学习,开发者可以掌握如何利用Spring来构建松散耦合、测试驱动和基于组件的应用程序。 4. Struts1.3...

    《轻量级Java EE企业应用实战(第三版) 第4章第1节的源代码

    7. **Spring框架**:Spring是Java EE开发中的核心框架,提供AOP(面向切面编程)、DI、事务管理等功能。如果涉及Spring,代码可能包含配置XML文件或基于Java的配置,以及使用`@Component`、`@Service`、`@Repository...

    基于 coolq-http-api 的 java sdk, 使用 JFinal 框架.zip

    JFinal 提供了快速开发的功能,如自动化映射字段、拦截器、AOP(面向切面编程)支持等。在这个项目中,JFinal 被用来构建服务器端,处理来自 CoolQ HTTP API 的请求,并通过 SDK 进行相应的操作。 具体到这个名为 ...

    JAVA WEB开发源码

    3. **第三章:JSP** - JSP(JavaServer Pages)用于动态网页生成,讲解JSP语法、EL(Expression Language)和JSTL(JavaServer Pages Standard Tag Library)。 4. **第四章:MVC模式** - 介绍Model-View-...

    java web开发典型模块大全(11~22章)完整

    7. **Spring框架基础**(17章):Spring是Java企业级应用的核心框架,提供依赖注入、AOP(面向切面编程)、数据访问等服务。虽然这部分未包含,但了解Spring对Java Web开发极其重要。 8. **Struts和Hibernate集成**...

    从零开始学java web

    Spring是Java Web开发中最受欢迎的框架之一,提供依赖注入、AOP(面向切面编程)等功能。本章将介绍Spring的基本概念和配置。 第十章:Spring MVC与RESTful API Spring MVC是Spring框架的一部分,用于构建Web应用。...

    《Java语言程序设计(进阶篇)》 课后习题第27章代码chapter27.rar

    动态代理则可以创建在运行时生成的代理类,以提供额外的功能,如AOP(面向切面编程)。 5. **集合框架高级特性和并发容器**:可能包括`ConcurrentHashMap`、`CopyOnWriteArrayList`、`BlockingQueue`等并发容器的...

    java相关jar包

    Java相关jar包是一个重要的软件开发资源集合,主要涵盖了Spring框架的4.0版本,DOM处理库dom4j,以及AOP(面向切面编程)相关的类库,还有用于查看Java源码的MyEclipse反编译工具。这些组件在Java开发中扮演着不可或...

    轻量级Java EE 企业应用实战(第三版)

    7. **Spring框架**:Spring是轻量级Java EE开发的代表,提供了全面的解决方案,包括依赖注入、AOP(面向切面编程)、事务管理等,极大地简化了企业应用的开发。 8. **RESTful Web服务**:使用JAX-RS(Java API for ...

    Java开发典型模块大全源代码

    15. **第16章:Spring框架** - Spring是Java应用开发中的重要框架,涵盖了依赖注入、AOP(面向切面编程)、Spring Boot、Spring MVC等内容。 16. **第17章:MyBatis持久层框架** - MyBatis简化了数据库操作,结合...

Global site tag (gtag.js) - Google Analytics