Spring的AOP开发-基于xml配置的AOP

Spring的AOP开发-基于xml配置的AOP

xml方式AOP快速入门

通过配置文件的方式解决以下问题

  • 配置哪些包、哪些类、哪些方法需要被增强
  • 配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强

配置方式的设计、配置文件(注解),Spring已经帮我们封装好了

xml方式配置AOP的步骤:
1、 导入AOP相关坐标;
2、准备目标类、准备增强类,并配置给Spring管理;
3、配置切点表达式(哪些方法被增强);
4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)。

package com.luxifa.service;
public interface UserService {
	
	void show1();

	void show2();

}
package com.luxifa.service.impl;
public class UserServiceImpl implements UserService {
	
	@Override
	public void show1() {
		System.out.println("show1...")
	}
	
    @Override
	void show2() {
		System.out.println("show2...")
	}

}

package com.luxifa.advice;

//增强类.内部提供增强方法
public class MyAdvice {
	
	public void beforeAdvice() {
		System.out.println("前置的增强...");
	}
	
	public void afterAdvice() {
		System.out.println("后置的增强...");
	}
}

<!--配置目标类-->
<bean id="userService" class="com.luxifa.service.impl.UserServiceImpl"/><bean>
<!--配置的通知类-->
<bean id="myAdvice" class="com.luxifa.advice.MyAdvice"></bean>

<!--aop配置-->
<aop:config>
	<!--配置切点表达式,目的是要指定哪些方法被增强-->
	<aop:pointcut id="myPoincut" expression="execution(void com.luxifa.service.impl.UserServiceImpl.show1())"/>
	<!--配置织入,目的是要执行哪些切点与哪些通知进行结合-->
	<aop:aspect ref="myAdvice">
		<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
	</aop:aspect>
</aop:config>

测试类:

public class ApplicationContextTest {
	public static void main(String[] args) {
		
		ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService userService = app.getBean(UserService.class);
		userService.show1();
	}
}

控制台打印:

前置的增强....
show1....

xml方式AOP配置详解

  • 切点表达式的配置方式
    切点表达式的配置方式有两种,直接将切点表达式配置在通知上,也可以将切点表达式抽取到外面,在通知上进行引用
<aop:config>
   <!--配置切点表达式,对哪些方法进行增强-->
   <aop:pointcut id="myPoincut" expression="execution(void com.luxifa.service.impl.UserServiceImpl.show1())"/>
   <!--切面=切点+通知-->
   <aop:aspect ref="myAdvice">
   	<!--指定前置通知方法是beforeAdvice-->
   	<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
   	<!--指定后置通知方法是afterAdvice-->
   	<aop:after-returning method="afterAdvice" pointcut="excution(void com.luxifa.service.impl.UserServiceImpl.show1())"/>
   </aop:aspect>
</aop:config>
  • 切点表达式的配置语法
    切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:
execution([访问修饰符]返回值类型 包名.类名.方法名(参数))

其中:

  • 访问修饰符可以省略不写;
  • 返回值的类型、某一级包名、类名、方法名 可以使用*表示任意;
  • 包名与类型之间使用单点 . 表示该包下的累,使用双点 … 表示该包及其子包下的类;
  • 参数列表可以使用两个点 … 表示任意参数。

切点表达式举例:

//表示访问修饰符为public、无返回值、在com.luxifa.aop包下的TargetImpl类的无参方法show
execution(public void com.luxifa.aop.TargetImpl.show())

//表示com.luxifa.aop包下的TargetImpl类的任意方法
execution(* com.luxifa.aop.TargetImpl.*.(..))

//表示com.luxifa.aop包下的任意类的任意方法
execution(* com.luxifa.aop.*.*(..))

//表示om.luxifa.aop包及其子包下的任意类的任意方法
execution(* com.luxifa.aop..*.*(..))

//表示任意包中的任意类的任意方法
execution(* *..*.*(..))
  • 通知的类型

AspectJ的通知由以下五种类型

通知名称配置方式执行时机
前置通知aop:before目标方法执行之前执行
后置通知aop:after-returning目标方法执行之后执行,目标方法异常时,不再执行
环绕通知aop:around目标方法执行前后执行,目标方法异常时,环绕后方法不再执行
异常通知aop:after-throwing目标方法抛出异常时执行
最终通知aop:after不管目标方法是否有异常,最终都会执行

环绕通知:

package com.luxifa.service;
public interface UserService {
	
	void show1();

	void show2();

}
package com.luxifa.service.impl;
public class UserServiceImpl implements UserService {
	
	@Override
	public void show1() {
		System.out.println("show1...")
	}
	
    @Override
	void show2() {
		System.out.println("show2...")
	}

}

package com.luxifa.advice;

//增强类.内部提供增强方法
public class MyAdvice {
	
	public void beforeAdvice() {
		System.out.println("前置的增强...");
	}
	
	public void afterReturningAdvice() {
		System.out.println("后置的增强...");
	}
	
	public  Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		System.out.println("环绕前的增强...");
	    //执行目标方法
	    Object res = proceedingJoinPoint.proceed();
	    System.out.println("环绕后的增强...");
	    return res;
	}
}

<!--配置目标类-->
<bean id="userService" class="com.luxifa.service.impl.UserServiceImpl"/><bean>
<!--配置的通知类-->
<bean id="myAdvice" class="com.luxifa.advice.MyAdvice"></bean>

<!--aop配置-->
<aop:config>
	<!--配置切点表达式,目的是要指定哪些方法被增强-->
	<aop:pointcut id="myPoincut" expression="execution(void com.luxifa.service.impl.UserServiceImpl.show1())"/>
	<aop:pointcut id="myPoincut2" expression="execution(* com.luxifa.service.impl.*.*(..))"/>
	<!--配置织入,目的是要执行哪些切点与哪些通知进行结合-->
	<aop:aspect ref="myAdvice">
		<!--环绕通知合-->
		<aop:around method="around" pointcut-ref="myPointcut2"/>
	</aop:aspect>
</aop:config>

通知方法在被调用时,Spring可以为其传递一些必要的参数

参数类型作用
JoinPoint连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息
ProceedingJoinPointJoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法
Throwable异常对象,使用在异常通知类中,需要在配置文件中指出异常对象名称

JointPoint对象

public void 通知方法名称(JointPoint joinPoint) {
	//获得目标方法的参数
	System.out.println(joinPoint.getArgs());
	//获得目标对象
	System.out.println(joinPoint.getTarget());
	//获得精确的切点表达式信息
	System.out.println(joinPoint.getStaticPart());
}

ProceedingJoinPoint对象

public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
	//获得目标方法的参数
	System.out.println(joinPoint.getArgs());
	//获得目标对象
	System.out.println(joinPoint.getTarget());
	//获得精确的切点表达式信息
	System.out.println(joinPoint.getStaticPart());
	//执行目标方法
	Object result = joinPoint.proceed();
	//返回目标方法返回值
	return result;
}

Throwable 对象

public void afterThrowing(JointPoint joinPoint,Throwable th) {
	//获得异常信息
	System.out.println("异常对象是:"+th+"异常信息是:"+th.getMessage());
}
<aop:after-throwing method="afterThrowing" pointcut-ref="mypointcut" throwing="th"/>
  • AOP的配置的两种方式

AOP配置的两种语法形式
AOP的xml有两种配置方式,如下:

  • 使用advisor配置切面
  • 使用aspect配置切面

Spring定义了一个Advice接口,实现了该接口的类都可以作为通知类出现

public interface Advice{
}

advisor需要的通知类需要实现Advice的子功能接口,例如:MethodBeforeAdvice、AfterReturningAdvice等,是通过实现的接口去确定具备哪些通知增强的。

AOP配置的两种语法形式不同点
语法形式不同:

  • advisor是通过实现接口来确定通知的类型
  • aspect是通过配置确认通知的类型,更加灵活

可配置的切面数量不同:

  • 一个advisor只能配置一个固定通知和一个切点表达式
  • 一个aspect可以配置多个通知和多个切点表达式任意组合

使用场景不同:

  • 允许随意搭配情况下可以使用aspect进行配置
  • 如果通知类型单一、切面单一的情况下可以使用advisor进行配置
  • 在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如Spring事务控制的配置

xml方式AOP原理剖析

两种生成动态代理对象的方式,一种是基于JDK,一种基于Chlib

代理技术使用条件配置方式
JDK动态代理技术目标类有接口,是基于接口动态生成实现类的代理对象目标类有接口的情况下,默认方式
Cglib动态代理技术目标类无接口且不能使用final修饰,是基于被代理对象动态生成子对象为代理对象目标类无接口时,默认使用该方式;目标类有接口时,手动配置aop:config

Cglib基于超类的动态代理

//目标对象
Target target = new Target();
//通知对象
Advices advices = new Advices();
//增强器对象
Enhancer enhancer = new Enhancer();
//增强器设置父类
enhancer.setSuperclass(Target.class);
//增强器设置回调
enhancer.setCallback((MethodInterceptor)(o.method.methodProxy)->{
	advice.before();
	Object object = method.invoke(target,Objects);
	advice.afterReturning();
	return result;
});
//创建代理对象
Target targetProxy = (Target)enhancer.create();
//测试
String result = targetProxy.show("路西法");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值