要进行AOP编程,首先我们要在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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
</beans>
Spring提供了两种切面使用方式,实际工作中我们可以选用其中一种:- 基于XML配置方式进行AOP开发。
- 基于注解方式进行AOP开发。
com.springsource.net.sf.cglib-2.2.0.jar:cglib代理
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
org.springframework.aop-3.0.2.RELEASE.jar:spring的面向切面编程,提供AOP(面向切面编程)实现
org.springframework.aspects-3.0.2.RELEASE.jar:spring提供对AspectJ框架的整合
基于XML配置—前置通知:
IUserManager.java
package com.xbmu.e.aop.xml.a_before;
public interface IUserManager {
void saveUser(String username,String password);
void updateUser(String username,String password);
void deleteUser(String username);
String findUser(String username);
}
UserManagerImpl.javapackage com.xbmu.e.aop.xml.a_before;
public class UserManagerImpl implements IUserManager{
@Override
public void saveUser(String username, String password) {
System.out.println("UserManagerImpl---saveUser");
}
@Override
public void updateUser(String username, String password) {
System.out.println("UserManagerImpl---updateUser");
}
@Override
public void deleteUser(String username) {
System.out.println("UserManagerImpl---deleteUser");
}
@Override
public String findUser(String username) {
System.out.println("UserManagerImpl---findUser");
return username;
}
}
Security.javapackage com.xbmu.e.aop.xml.a_before;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
*/
public void checkSecurity(JoinPoint joinPoint){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
}
}
App.javapackage com.xbmu.e.aop.xml.a_before;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/a_before/beans.xml");
IUserManager userManager = (IUserManager) ctx.getBean("userManage");
/**
* 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
* 当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
*/
userManager.saveUser("张三", "123");
System.out.println("**************************************");
userManager.updateUser("李四", "456");
}
}
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
<!-- 声明一个切面,该切面不具有灵魂 -->
<bean id="security" class="com.xbmu.e.aop.xml.a_before.Security"></bean>
<bean id="userManage" class="com.xbmu.e.aop.xml.a_before.UserManagerImpl"></bean>
<!--
声明一个切入点
通知、切入点、通知关联切入点等操作都要放置到aop:config中
注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
-->
<aop:config>
<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
<aop:aspect id="security1" ref="security">
<!--
声明切入点
id:为切入点起个名字
expression:表达式,定义切入点
-->
<aop:pointcut id="pointcutSave"
expression="execution(* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..))" />
<!--
将切入点和通知进行关联
aop:before:前置通知
* 在访问切入点之前进行通知
* 如果在通知中出现异常,可以阻止程序到切入点
-->
<aop:before method="checkSecurity" pointcut-ref="pointcutSave"/>
</aop:aspect>
</aop:config>
<!--
aop:pointcut:expression详细说明:?号表示该参数不是必须的
execution(modifiers-pattern? :修饰符:不是必须的,如public,private等。
public * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
ret-type-pattern :返回类型
String com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
说明返回类型是String
Integer com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
说明返回类型是Integer
*com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
可以接收任意的返回类型
declaring-type-pattern? :不是必须的,声明包中类的路径,
本例(com.xbmu.e.aop.xml.a_before.UserManagerImpl)
com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
name-pattern:表示方法的名称
*com.xbmu.e.aop.xml.a_before.UserManagerImpl.saveUser(..)
此时找saveUser的方法
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.*(..)
此时找该UserManageImpl类中所有的方法
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
此时找该UserManageImpl类中以save开头的所有方法
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*get(..)
此时找该UserManageImpl类中以save开头,get结束的所有方法
(param-pattern):方法的参数
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*():'
匹配了一个不接受任何参数的方法
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..):
而(..)匹配了一个接受任意数量参数的方法(零或者更多)
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(*):
模式(*)匹配了一个接受一个任何类型的参数的方法
* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(*,String):
模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。
(throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。
* 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*,
它代表了匹配任意的返回类型。一个全限定的类型名将只会匹配返回给定类型的方法。
* 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。
* 参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。
模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型,
第二个则必须是String类型
任意公共方法的执行:
execution(public * *(..))
任何一个名字以“set”开始的方法的执行:
execution(* set*(..))
AccountService接口定义的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
在service包中定义的任意方法的执行
execution(* com.xyz.service.*.*(..))
在service包或其子包中定义的任意方法的执行:(项目经常用到)
execution(* com.xyz.service..*.*(..))
-->
</beans>
运行结果:如果在通知中出现异常,可以阻止程序到切入点
Security.java
package com.xbmu.e.aop.xml.a_before;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
*/
public void checkSecurity(JoinPoint joinPoint){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
//阻止到切入点的程序,抛出异常
if(true){
throw new RuntimeException("出现异常");
}
}
}
运行结果:
基于XML配置—后置通知:
Security.java
package com.xbmu.e.aop.xml.b_afterreturn;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
* spring容器中的定义:
* <aop:after-returning pointcut-ref="pointcutSave"
method="checkSecurity" returning="returnvalue"/>
* 后置通知获取切入点的返回值
* 注意:返回是一个Object对象
* Object的参数名称必须是returning属性的值
* Object returnvalue必须要放置到JoinPoint的后面
*/
public void checkSecurity(JoinPoint joinPoint,Object returnvalue){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
System.out.println("返回值:"+returnvalue);
}
}
App.javapackage com.xbmu.e.aop.xml.b_afterreturn;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/b_afterreturn/beans.xml");
IUserManager userManager = (IUserManager) ctx.getBean("userManage");
/**
* 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
*/
userManager.saveUser("张三", "123");
System.out.println("**************************************");
userManager.updateUser("李四", "456");
System.out.println("**************************************");
String str = userManager.findUser("赵六");
System.out.println("str:"+str);
}
}
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
<!-- 声明一个切面,该切面不具有灵魂 -->
<bean id="security" class="com.xbmu.e.aop.xml.b_afterreturn.Security"></bean>
<bean id="userManage" class="com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl"></bean>
<!--
声明一个切入点
通知、切入点、通知关联切入点等操作都要放置到aop:config中
注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
-->
<aop:config>
<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
<aop:aspect id="security1" ref="security">
<!--
声明切入点
id:为切入点起个名字
expression:表达式,定义切入点
-->
<aop:pointcut id="pointcutSave"
expression="execution(* com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl.save*(..))" />
<aop:pointcut id="pointcutFind"
expression="execution(* com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl.find*(..))" />
<!--
将切入点和通知进行关联
aop:after-returning:后置通知
* 在访问切入点之前进行通知
* 如果在通知中出现异常,可以阻止程序到切入点
returning=在通知中可以获取到切入点的返回值
-->
<aop:after-returning pointcut-ref="pointcutSave" method="checkSecurity" returning="returnvalue"/>
<aop:after-returning pointcut-ref="pointcutFind" method="checkSecurity" returning="returnvalue"/>
</aop:aspect>
</aop:config>
</beans>
运行结果:
如果在通知中出现异常,可以阻止程序到切入点
Security.java
package com.xbmu.e.aop.xml.b_afterreturn;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
* spring容器中的定义:
* <aop:after-returning pointcut-ref="pointcutSave"
method="checkSecurity" returning="returnvalue"/>
* 后置通知获取切入点的返回值
* 注意:返回是一个Object对象
* Object的参数名称必须是returning属性的值
* Object returnvalue必须要放置到JoinPoint的后面
*/
public void checkSecurity(JoinPoint joinPoint,Object returnvalue){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
System.out.println("返回值:"+returnvalue);
//阻止到切入点的程序,抛出异常
if(true){
throw new RuntimeException("出现异常");
}
}
}
运行结果:基于XML配置—异常通知
Security.java
package com.xbmu.e.aop.xml.c_afterthrowing;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
* spring容器中的定义:
* <aop:after-returning pointcut-ref="pointcutSave"
method="checkSecurity" returning="returnvalue"/>
* 后置通知获取切入点的返回值
* 注意:返回是一个Object对象
* Object的参数名称必须是returning属性的值
* Object returnvalue必须要放置到JoinPoint的后面
*/
public void checkSecurity(JoinPoint joinPoint,Throwable throwExecution){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
System.out.println("异常:"+throwExecution);
}
}
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
<!-- 声明一个切面,该切面不具有灵魂 -->
<bean id="security" class="com.xbmu.e.aop.xml.c_afterthrowing.Security"></bean>
<bean id="userManage" class="com.xbmu.e.aop.xml.c_afterthrowing.UserManagerImpl"></bean>
<!--
声明一个切入点
通知、切入点、通知关联切入点等操作都要放置到aop:config中
注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
-->
<aop:config>
<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
<aop:aspect id="security1" ref="security">
<!--
声明切入点
id:为切入点起个名字
expression:表达式,定义切入点
-->
<aop:pointcut id="pointcutSave"
expression="execution(* com.xbmu.e.aop.xml.c_afterthrowing.UserManagerImpl.save*(..))" />
<!--
将切入点和通知进行关联
aop:after-throwing:异常通知
* 通知在切入点要抛出异常之后执行,如果切入点不抛出异常,此时不会执行通知
throwing="":用于在通知中查看切入点抛出的异常
-->
<aop:after-throwing pointcut-ref="pointcutSave" method="checkSecurity" throwing="throwExecution"/>
</aop:aspect>
</aop:config>
</beans>
运行结果:
通知在切入点要抛出异常之后执行,如果切入点不抛出异常,此时不会执行通知。
UserManagerImpl.java
package com.xbmu.e.aop.xml.c_afterthrowing;
public class UserManagerImpl implements IUserManager{
@Override
public void saveUser(String username, String password) {
System.out.println("UserManagerImpl---saveUser");
if(true){
throw new RuntimeException("出现异常");
}
}
@Override
public void updateUser(String username, String password) {
System.out.println("UserManagerImpl---updateUser");
}
@Override
public void deleteUser(String username) {
System.out.println("UserManagerImpl---deleteUser");
}
@Override
public String findUser(String username) {
System.out.println("UserManagerImpl---findUser");
return username;
}
}
基于XML配置—最终通知
Security.java
package com.xbmu.e.aop.xml.d_after;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
* 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
* (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
*
* org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
* getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
*
* @param joinPoint 获取连接点的一些信息(目标对象中的方法)
*/
public void checkSecurity(JoinPoint joinPoint){
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object[] args = joinPoint.getArgs();
if(null!=args && args.length>0){
for (Object obj : args) {
System.out.println("参数:"+obj);
}
}
}
}
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
<!-- 声明一个切面,该切面不具有灵魂 -->
<bean id="security" class="com.xbmu.e.aop.xml.d_after.Security"></bean>
<bean id="userManage" class="com.xbmu.e.aop.xml.d_after.UserManagerImpl"></bean>
<!--
声明一个切入点
通知、切入点、通知关联切入点等操作都要放置到aop:config中
注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
-->
<aop:config>
<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
<aop:aspect id="security1" ref="security">
<!--
声明切入点
id:为切入点起个名字
expression:表达式,定义切入点
-->
<aop:pointcut id="pointcutSave"
expression="execution(* com.xbmu.e.aop.xml.d_after.UserManagerImpl.save*(..))" />
<!--
将切入点和通知进行关联
aop:after:最终通知
* 最终通知在切入点无论是否抛出异常都会执行通知
-->
<aop:after pointcut-ref="pointcutSave" method="checkSecurity"/>
</aop:aspect>
</aop:config>
</beans>
App.javapackage com.xbmu.e.aop.xml.d_after;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/d_after/beans.xml");
IUserManager userManager = (IUserManager) ctx.getBean("userManage");
/**
* 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
*/
userManager.saveUser("张三", "123");
System.out.println("**************************************");
userManager.updateUser("李四", "456");
}
}
运行结果:最终通知在切入点无论是否抛出异常都会执行通知
UserManagerImpl.java
package com.xbmu.e.aop.xml.d_after;
public class UserManagerImpl implements IUserManager{
@Override
public void saveUser(String username, String password) {
System.out.println("UserManagerImpl---saveUser");
if(true){
throw new RuntimeException("出现异常");
}
}
@Override
public void updateUser(String username, String password) {
System.out.println("UserManagerImpl---updateUser");
}
@Override
public void deleteUser(String username) {
System.out.println("UserManagerImpl---deleteUser");
}
@Override
public String findUser(String username) {
System.out.println("UserManagerImpl---findUser");
return username;
}
}
基于XML配置—环绕通知
Security.java
package com.xbmu.e.aop.xml.e_around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
/**切面*/
public class Security {
/**通知*/
/**
*
* 如果是环绕通知:
* * 环绕通知在一个方法执行之前和之后执行。它使得通知有机会 在一个方法执行之前和执行之后运行。
* 而且它可以决定这个方法在什么时候执行,如何执行,甚至是否执行
* * 通知的第一个参数必须是 ProceedingJoinPoint类型。
* 在通知体内,调用 ProceedingJoinPoint的proceed()方法会导致 后台的连接点方法执行。
* 第一个参数:
* * ProceedingJoinPoint joinPoint,获取连接点的一些信息(目标对象中的方法)
* * 如果是环绕通知,可以有返回值,是一个Object对象
*/
public Object checkSecurity(ProceedingJoinPoint joinPoint){
Object returnValue = null;
try {
returnValue = joinPoint.proceed();//调切入点的方法
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("进行安全检查!");
System.out.println("连接点类:"+joinPoint.getClass());
System.out.println("目标对象:"+joinPoint.getTarget());
Signature signature = joinPoint.getSignature();
System.out.println("方法名称:"+signature.getName());
Object [] arg = joinPoint.getArgs();
if(arg!=null && arg.length>0){
for(Object o:arg){
System.out.println("参数:"+o);
}
}
return returnValue;
}
}
App.javapackage com.xbmu.e.aop.xml.e_around;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/e_around/beans.xml");
IUserManager userManager = (IUserManager) ctx.getBean("userManage");
/**
* 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
*/
userManager.saveUser("张三", "123");
System.out.println("**************************************");
userManager.updateUser("李四", "456");
}
}
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--
添加基于spring的aop切面的命名空间:添加:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
-->
<!-- 声明一个切面,该切面不具有灵魂 -->
<bean id="security" class="com.xbmu.e.aop.xml.e_around.Security"></bean>
<bean id="userManage" class="com.xbmu.e.aop.xml.e_around.UserManagerImpl"></bean>
<!--
声明一个切入点
通知、切入点、通知关联切入点等操作都要放置到aop:config中
注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
-->
<aop:config>
<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
<aop:aspect id="security1" ref="security">
<!--
声明切入点
id:为切入点起个名字
expression:表达式,定义切入点
-->
<aop:pointcut id="pointcutSave"
expression="execution(* com.xbmu.e.aop.xml.e_around.UserManagerImpl.save*(..))" />
<!--
将切入点和通知进行关联
aop:around:环绕通知
* 环绕通知表示可以在切入点的前后动态的执行通知
-->
<aop:around pointcut-ref="pointcutSave" method="checkSecurity"/>
</aop:aspect>
</aop:config>
</beans>
运行结果: