`

十二 spring的AOP编程

 
阅读更多
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.

joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)

Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.

Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知

Target(目标对象):代理的目标对象

Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.

Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.


采用注解方式实现spring的aop编程

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:aop="http://www.springframework.org/schema/aop"      
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
        <!-- 启动对@AspectJ注解的支持 -->
	<aop:aspectj-autoproxy/> 
</beans>

分析 xmlns:aop="http://www.springframework.org/schema/aop"  
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
 这些是引入aop的命名空间
引入了命名空间还不行 因为现在采用的是注解的方式实现aop编程
所以要启动对启动对@AspectJ注解的支持 <aop:aspectj-autoproxy/>  
当然在引入这个aop之前必须把spring的注解引入进来
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

然后引入aop的jar文件 lib/aspectj/aspectjweaver.jar和aspectjrt.jar lib/cglib/cglib-nodep-2.1_3.jar
如果要注解 如果要注解方式实现aop编程当然要把注解引入进来 lib\j2ee\common-annotations.jar
现在环境就搭建好了!

在做aop编程之前必须要理解这几个概念
切面:要对哪些业务bean(拦截的类)进行拦截
切入点:要对哪些方法进行拦截
通知:所谓通知就是拦截到的方法之后或者之前做的工作就叫通知

在进行aop编程之前必须要定义切面 定义切入点 定义通知

首先定义接口
package cn.itcast.service;

public interface PersonService {
	public void save(String name);
	public void update(String name, Integer id);
	public String getPersonName(Integer id);
}

定义测试的业务bean

package cn.itcast.service.impl;

import cn.itcast.service.PersonService;

public class PersonServiceBean implements PersonService {

	public String getPersonName(Integer id) {
		System.out.println("我是getPersonName()方法");
		return "xxx";
	}

	public void save(String name) {
		throw new RuntimeException("我爱例外");
		//System.out.println("我是save()方法");
	}

	public void update(String name, Integer id) {
		System.out.println("我是update()方法");
	}

}


定义切面 并且在切面中定义切入点 @Aspect是定义切面的注释 


package cn.itcast.service;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
 * 切面
 *
 */
@Aspect
public class MyInterceptor {
	@Pointcut("execution (* cn.itcast.service.impl.PersonServiceBean..*(..))")
	private void anyMethod() {}//声明一个切入点
	
	@Before("anyMethod() && args(name)")
	public void doAccessCheck(String name) {
		System.out.println("前置通知:"+ name);
	}
	@AfterReturning(pointcut="anyMethod()",returning="result")
	public void doAfterReturning(String result) {
		System.out.println("后置通知:"+ result);
	}
	@After("anyMethod()")
	public void doAfter() {
		System.out.println("最终通知");
	}
	@AfterThrowing(pointcut="anyMethod()",throwing="e")
	public void doAfterThrowing(Exception e) {
		System.out.println("例外通知:"+ e);
	}
	
	@Around("anyMethod()")
	public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
		//if(){//判断用户是否在权限
		System.out.println("进入方法");
		Object result = pjp.proceed();
		System.out.println("退出方法");
		//}
		return result;
	}
	
}

理解:现在理解切面是什么了吧,说白了,其实就是一个拦截器,一个生成代理类的拦截器
@Pointcut("execution (* cn.itcast.service.impl.PersonServiceBean..*(..))") 这是什么意思呢
这里Pointcut是定义切入点 execution 这里表示的执行的表达式 
* cn.itcast.service.impl.PersonServiceBean.*(..) 这第一个*表示的任何返回值类型
cn.itcast.service.impl.PersonServiceBean 这里表示对哪些包下的类进行拦截 这里表示对
cn.itcast.service.impl.PersonServiceBean包下的类进行拦截
第一个.. 表示对包下的子包的类也要进行拦截 
第二个*表示的所有的方法进行拦截
(..) 这里表示方法参数可以任意 可以有0个 多个或者一个

private void anyMethod() {}//声明一个切入点 这里是定义切入点的名称

@Before("anyMethod() && args(name)")
	public void doAccessCheck(String name) {
		System.out.println("前置通知:"+ name);
	}

这里定义的是前置通知 表示doAccessCheck方法为前置通知要执行的方法
当前这是前置通知,表示的是拦截到方法执行之前要执行的方法叫做通知


args是指定参数 也是作为条件存在的 可以不指定



如果换做基于xml方式做aop的配置呢
首先把在做切面的的类的切入注释全部删掉 
然后在配置文件中去声明
   <!--配置业务bean-->
        <bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>
	<!--把切面的类交给spring去管理-->
        <bean id="aspetbean" class="cn.itcast.service.MyInterceptor"/>
	<!--定义切面-->
        <aop:config>
	       <!--引入切面的类注册到切面中来-->
        	<aop:aspect id="asp" ref="aspetbean">
		        <!--定义一个切面 切入点名称mycut 条件是execution(* cn.itcast.service..*.*(..))-->
        		<aop:pointcut id="mycut" expression="execution(* cn.itcast.service..*.*(..))"/>
			<!--定义前置通知 引入的切入点mycut 前置通知的执行方法doAccessCheck-->
        		<aop:before pointcut-ref="mycut" method="doAccessCheck"/>
			<!--定义后置通知 引入的切入点mycut 后置通知的执行方法doAfterReturning -->
        		<aop:after-returning pointcut-ref="mycut" method="doAfterReturning"/>
			  <!--例外通知 引入的切入点mycut 例外通知执行的方法doAfterThrowing-->
			  	<aop:after-throwing pointcut-ref="mycut" method="doAfterThrowing"/>
				<!--最终通知 引入的切入点mycut 最终通知执行的方法doAfter -->
			  	<aop:after pointcut-ref="mycut" method="doAfter"/>
				<!--环绕通知 引入的切入点mycut 环绕通知执行的方法doBasicProfiling -->
			  	<aop:around pointcut-ref="mycut" method="doBasicProfiling"/>
        	</aop:aspect>
        </aop:config>


注意:环绕通知是一个很重要的方法,在这里面可以做权限的拦截


现在我们重点来学习下切入点的表达式应该如何去写
execution(* cn.pf.aop.service.impl.PersonServiceBean.*(..))
所有非final方法

execution(!void cn.pf.aop.service.impl.PersonServiceBean.*(..))
非void非final方法

execution(java.lang.String cn.pf.aop.service.impl.PersonServiceBean.*(..))
非final且返回类型为String的方法


execution(java.lang.String cn.pf.aop.service.impl.PersonServiceBean.*(java.lang.String,..))
第一个参数为String的非final方法

execution(* cn.pf.aop.service.impl..*.*(..))
对包下所有类进行拦截

至此 spring的aop编程已经全部结束!

end 完毕!

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics