现在的位置: 首页 > 综合 > 正文

Spring笔记——aop

2014年09月05日 ⁄ 综合 ⁄ 共 4878字 ⁄ 字号 评论关闭


aop的概念(浅谈辄止):
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)(比如被拦截的方法)
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.


使用Spring进行面向切面(AOP)编程(以下是注解方式,也可以通过Xml方式):
1:首先我们要在spring的配置文件中引入aop命名空间
2:启动对@AspectJ注解的支持(蓝色部分),凡是没被拦截的方法则直接执行
3:编写切面类,下面已写的类LogPrint
4:通过配置<bean>把类交给spring管理
5:引入夹包:
核心包spring.jar输出日志信息包commons-logging.jar
如果使用了切面编程(AOP),还需要下列jar文件aspectjweaver.jar和aspectjrt.jarcglib-nodep-2.1_3.jar


配置文件:

配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>// 注入解析aop中使用到的注解的处理器

//通过bean让类交给Spring管理
<bean id="orderservice" class="cn.itcast.service.OrderServiceBean"/>
<bean id="log" class="cn.itcast.service.LogPrint"/>  //
</beans>


切面类:
@Aspect   //切面注解
public class LogPrint {
@Pointcut(“execution(* cn.itcast.service..*.*(..))”)// 拦截切入点,(后面一句周亮总结)连接点(在spring指方法)的集合是切入点,
 private void anyMethod() {}//声明一个切入点
//*任意返回类型,cn.itcast.service包名,..子包,*包中的任意类,.*类中的任意方法,(..)方法参数可以有也可没有
@Before(“anyMethod() && args(userName)”)//定义前置通知,只处理参数类型为String的方法
public void doAccessCheck(String userName) {
System.out.pirntln(“前置通知”);
}
//定义后置通知,只处理返回类型为String的方法,但是如果返回值是void的类型,也会处理,
@AfterReturning(pointcut=“anyMethod()”,returning=“revalue”)
public void doReturnCheck(String revalue) {  // revalue存放拦截函数执行的返回值,如果返回类型是void,则revalue为null
System.out.pirntln(“后置通知”);
}
@AfterThrowing(pointcut=“anyMethod()”, throwing=“ex”)//定义例外通知,并接受处理例外ex
      public void doExceptionAction(Exception ex) {
System.out.pirntln(“例外通知”);
}
@After("anyMethod()")//定义最终通知
public void doReleaseAction() {
System.out.pirntln(“最终通知”);
}
@Around("anyMethod()")//环绕通知
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { // 参数类型不可变
//if()判断是否有权限
System.out.pirntln(“进入方法”);
Object result= pjp.proceed();    // 执行该方法才能执行目标对象的方法
System.out.println(“退出方法“);
Return result;
//注: pjp.proceed();会执行被拦截的业务方法,如果被拦截的页面方法还存在切面,则该方法会执行下一个切面的拦截方法再执行业务方法,如果不执行该方法,则下一个切面的方法和业务方法都不会执行。
}
}



疑问?:在spring的aop编程中是否只有被拦截的切入点所对应的类即: @Pointcut(“execution(* cn.itcast.service..*.*(..))”)//被拦截的切入点中所涉及的类才使用了动态代理,而其他类则没有使用,而是直接利用了反射机制返回类该类的实例?

测试:
ApplicationContext cxt = new ClassPathXmlApplicationContext("spring.xml");
OrderServiceBean service = cxt.getBean("orderservice");
service.save("xxx");
控制台输出结果:
前置通知
进入方法
后置通知
最终通知
退出方法


注:可以在环绕通知解决处理其它通知的事情,从而没必要写其它通知。



Spring在生成动态代理时,是使用使用jdk的Proxy来生成代理对象,还是使用使用CGLIB的Enhancer 生成代理?处理依据为:

当目标类实现了接口,我们可以使用jdk的Proxy来生成代理对象,否则使用CGLIB。

以下分别使用JDK和CGLIB来实现动态代理案例,加深对动态代理的认识及Spring中的通知在具体方法处理中的位置。

1.JDK实现的动态代理:
public class JDKProxy implements InvocationHandler {
	private Object targetObject;//代理的目标对象
	public Object createProxyInstance(Object targetObject){   // 创建代理对象,前提目标类必须实现接口,即被代理的方法都是接口方法,
		this.targetObject = targetObject;
/*  
* 第一个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器
* 第二个参数设置代理类实现的接口
第三个参数设置回调对象,当代理对象的方法被调用时,会委派给该参数指定对象的invoke方法
(即该方法的返回的代理对象的方法被调用时,会让JDKProxy对象的invoke方法来执行。)
*/
		return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
				this.targetObject.getClass().getInterfaces(), this);// 代理类实现目标类的所有接口方法
	}
	// 回调方法,当代理类的相应接口被执行时便执行
	// 参数:代理对象,代理对象被调用的方法(拦截到的方法),被调用方法传进的参数
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if( (String)args[0].equal(“mmm”)
		return method.invoke(this.targetObject, args);//把方法调用委派给目标对象
		else
		return null;
	}
}
当目标类实现了接口,我们可以使用jdk的Proxy来生成代理对象。


2.使用CGLIB生成代理(需要引入cglib-nodep-2.1_3.jar)
public class CGLIBProxy implements MethodInterceptor {
	private Object targetObject;//代理的目标对象	
	public Object createProxyInstance(Object targetObject){// 被代理对象可以不用继承接口
		this.targetObject = targetObject;
		Enhancer enhancer = new Enhancer();//该类用于生成代理对象
		enhancer.setSuperclass(this.targetObject.getClass());//设置父类,对非final所有方法进行覆盖同时增加自身代码
		enhancer.setCallback(this);//设置回调,用对象为本身
		return enhancer.create();
	}
	// 代理对象,被拦截的方法,方法参数,方法代理对象
	public Object intercept(Object proxy, Method method, Object[] args,
			MethodProxy methodProxy) throws Throwable { // 环绕通知<pre code_snippet_id="358592" snippet_file_name="blog_20140522_6_5186680" name="code" class="java"><span style="white-space:pre"></span><pre code_snippet_id="358592" snippet_file_name="blog_20140522_6_5186680" name="code" class="java"><span style="white-space:pre"></span><pre code_snippet_id="358592" snippet_file_name="blog_20140522_6_5186680" name="code" class="java">Object result = null;
If( args…..)
{
// 前置通知  advice(); 
Try{
result methodProxy.invoke(this.targetObject, args);
//后置通知aferadvice();
}catch(Exception)
{
//例外通知exceptiondvice();
}finally{
//最终通知finallyadvice();
}
}
Return result;
	}


}CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。



抱歉!评论已关闭.