1、通过xml配置文件实现AOP
流程:
- 将所有的切片操作放到一个类中。
- 在xml配置文件中,通过扫描器、手动配置两种方式,得到被代理类对象和切片类对象。
- 通过
<aop:config>
标签,配置切面,切入点以及增强哪些方法。 - main函数中只需解析xml文件,得到返回的代理类对象,然后用接口或代理类去引用它。
切片类:
//配置扫描器别名
@Component("xmlAspect")
public class XMLAspectDemo {
// 前置通知
public void mybefore(JoinPoint joinPoint) {
System.out.print("调用方法之前起作用...");
System.out.print("代理对象的对象:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
System.out.print("before 方法结束........");
}
// 后置通知
public Object myAfterReturn(JoinPoint joinPoint) {
System.out.print("调用方法之后...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
return null;
}
/**
* 环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}
JoinPoint是插入点。类似的还有PointCut,advice,advicer。
xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 使用扫描器创建对象 -->
<context:component-scan base-package="com.hugeyurt.aspect"/>
<!-- 手动创建对象 -->
<!-- <bean id="myAspect" class="com.hugeyurt.aspect.XMLAspectDemo" />
<bean id="serviceDemo2" class = "com.hugeyurt.aspect.ServiceDemo2" /> -->
<!-- aop编程 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="xmlAspect">
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut expression="execution(* com.hugeyurt.aspect.*.*(..))"
id="myPointCut" />
<!-- 第一个*:所有该全限定名 。 第二个*:所有类。 第三个*:所有方法。 括号:所有形参 -->
<!-- 3.2 关联通知Advice和切入点pointCut -->
<!-- 3.2.1 前置通知 -->
<aop:before method="mybefore" pointcut-ref="myPointCut" />
<!-- 3.2.2 后置通知,在方法返回之后执行,就可以获得返回值
returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
<!-- <aop:after-returning method="myAfterReturning"
pointcut-ref="myPointCut" returning="point" /> -->
<!-- 3.2.3 环绕通知 -->
<!-- <aop:around method="myAround" pointcut-ref="myPointCut" /> -->
<!-- 3.2.4 抛出通知:用于处理程序发生异常-->
<!-- * 注意:如果程序没有异常,将不会执行增强 -->
<!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
<!-- <aop:after-throwing method="myAfterThrowing"
pointcut-ref="myPointCut" throwing="e" /> -->
<!-- 3.2.5 最终通知:无论程序发生任何事情,都将执行 -->
<!-- <aop:after method="myAfter" pointcut-ref="myPointCut" /> -->
</aop:aspect>
</aop:config>
</beans>
main函数:
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
// 1 从spring容器获得内容
IAopDemo demo = (IAopDemo) appContext.getBean("serviceDemoOne");
//ServiceDemo2 demo = (ServiceDemo2) appContext.getBean("serviceDemo2");
// 2 执行方法
demo.printA();
//demo.printName();
}
这种方式比起上一个版本,将所有的切片方式放到一个类中,并且可以对被代理类的任意方法进行切片处理,在XML配置文件中也可以通过扫描器的方式获取所有对象,更加灵活。
但是XML配置文件过于冗杂,繁琐。下个版本将会解决这个问题。
2、简化xml,实现AOP
流程:
- 通过@Component注解获得切面类
- 通过@Aspect注解获得具体切面信息
- 通过@Before(“自己定义的方法”)等注解,决定使用哪个切片
- main正常调用
xml配置文件:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 指定需要扫描的包,使注解生效 -->
<context:component-scan base-package="com.hugeyurt.aspect.annotation" />
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy />
</beans>
切面类:
/**
* 切面类,在此类中编写通知
*/
@Component
@Aspect
public class AspectAnnotation {
// 定义切入点表达式
@Pointcut("execution(* com.hugeyurt.aspect.annotation.*.*(..))")
// 使用一个返回值为void、方法体为空的方法来命名切入点
private void myPointCut(){}
// 前置通知
@Before("myPointCut()")
public void myBeforeafdasf(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
String method=joinPoint.getTarget().getClass().getName()+"-"+joinPoint.getSignature().getName();
System.out.println(method);
Object[] args=joinPoint.getArgs();
for (Object object : args)
{
System.out.println(object.getClass().getName());
System.out.println(object.toString());
}
}
// 后置通知
//@AfterReturning(value="myPointCut()")
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被值入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
// 环绕通知
//@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
//@AfterThrowing(value="myPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
//@After("myPointCut()")
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}
main函数:
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "beansAnnotation.xml" });
// 1 从spring容器获得内容
ServiceDemo demo = (ServiceDemo) appContext.getBean("serviceDemo");
IHello demo2 = (IHello) appContext.getBean("serviceDemo2");
// 2 执行方法
demo.printName("kitty",89);
demo2.sayHello("hello");
}
对比上个版本,这个版本更加简便。
通过三种注解,获得了切面类的所有信息,并通过spring容器实现了切片功能。通过正则表达式可以在任意方法处实现切片操作。