前面有一篇利用Annotation实现AOP,现在记录一下通过XML来实现该功能。
以下过程中,前期准备与上一篇Spring学习——AOP由Annotation实现类似,可以简单看一下。
1、 在beans.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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 打开Spring的Annotation -->
<context:annotation-config/>
<!-- 设定Spring去哪些包中找Annotation -->
<context:component-scan base-package="spring"/>
</beans>
2、创建一个需要实现动态代理的类
//实现代理的类
public class LogAspect {
public void logStart() {
Logger.info("加入日志");
}
}
//这个是功能类
public class Logger {
public static void info(String info) {
System.out.println("----" + info);
}
}
3、导入aspect包
Spring使用的是AspectJ包来实现AOP的,所以需要导入这个包
4、注解声明
不同于使用Annotation方式实现AOP,xml实现方式,只需要告知Spring,LogAspect的存在就可以。
@Component("logAspect")
public class LogAspect {
public void logStart(JoinPoint jPoint) {
//得到执行的对象
System.out.println(jPoint.getTarget());
//得到执行的方法
System.out.println(jPoint.getSignature().getName());
Logger.info("加入日志");
}
public void logEnd(JoinPoint jPoint) {
Logger.info("方法调用结束");
}
public void logAround(ProceedingJoinPoint jPoint) {
Logger.info("开始在Around加入日志");
try {
//执行方法
jPoint.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Logger.info("结束Around");
}
}
5、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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 打开Spring的Annotation -->
<context:annotation-config />
<!-- 设定Spring去那些包中找Annotation -->
<context:component-scan base-package="spring" />
<aop:config>
<!-- 定义切面 -->
<aop:aspect id="myLogAspect" ref="logAspect">
<!-- 在那些位置加入相应的Aspect -->
<aop:pointcut
expression="execution(* spring.dao.*.add*(..))||execution(* spring.dao.*.delete*(..))"
id="logPointCut" />
<aop:before method="logStart" pointcut-ref="logPointCut"/>
<aop:after method="logEnd" pointcut-ref="logPointCut"/>
<aop:around method="logAround" pointcut-ref="logPointCut"/>
</aop:aspect>
</aop:config>
</beans>
测试
spring.dao中的类
接口
public interface IUserDao {
public void add(User user);
public void delete(int id);
public User load(int id);
}
实现类
@Repository("userDao")
public class UserDao implements IUserDao {
@Override
public void add(User user) {
System.out.println("添加了 " + user.getName());
}
@Override
public void delete(int id) {
System.out.println("删除了" + id);
}
@Override
public User load(int id) {
System.out.println("加载了 " + id);
return null;
}
}
测试方法
@Test
public void testUser01() {
IUserDao dao=(IUserDao) factory.getBean("userDao");
User user = new User(1,"猴子");
dao.add(user);
}
测试结果
spring.dao.UserDao@2d0399f4
add
----加入日志
----开始在Around加入日志
添加了 猴子
----结束Around
----方法调用结束
顺序问题
如果看过上一篇文章,应该还记得,@Around里面有proceed方法,如果不执行,则不会执行方法。上一篇的结果是拦截了@Before的响应。
这次我们也将方法屏蔽,结果为:
spring.dao.UserDao@2d0399f4
add
----加入日志
----开始在Around加入日志
----结束Around
----方法调用结束
上面两个结果对比后发现,logStart方法执行了,并且在logAround方法之前执行。这样和上一篇得出来的结论不一致,所以我调换了beans.xml里面的顺序:
<aop:around method="logAround" pointcut-ref="logPointCut"/>
<aop:before method="logStart" pointcut-ref="logPointCut"/>
<aop:after method="logEnd" pointcut-ref="logPointCut"/>
测试结果:
----开始在Around加入日志
----结束Around
----方法调用结束
即如果<aop:aroud/>
在<aop:before/>
之前,则如果不调用proceed方法,<aop:before/>
不会响应。
最后
具体使用哪种方式,取决于个人习惯,上面的顺序问题,只是记录下来,提醒一下可能存在这种问题,其并不会对项目有多大影响。
如果有错误,请留言指出,我会第一时间回复并修改。