Spring之异常抛出增强&&最终增强&&环绕增强&&注解

    科技2025-06-06  84

    异常抛出增强

    异常抛出增强(afterThrowing):在目标方法抛出异常时织入增强处理

    //异常增强:afterThrowing //运行时异常:RuntimeException public void afterThrowing(JoinPoint jp, RuntimeException e) { log.error("异常抛出增强:" + jp.getSignature().getName() + "方法发生异常:" + e); }

    Application配置文件:

    <!--aop:after-throwing:异常增强,在目标方法抛出异常时织入增强处理 异常抛出增强 e代表收集异常信息的--> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>

    最终增强

    最终增强:无论方法是否抛出,都会在目标方法最后织入增强处理,即:该增强都会得到执行。 ​ 类似于异常处理机制中的finally块的作用,一般用于释放资源。

    //最终增强 //无论方法是否抛出,都会在目标方法最后织入增强处理,即:该增强都会得到执行。 //类似于异常处理机制中的finally块的作用,一般用于释放资源。 public void afterLogger(JoinPoint jp) { log.info("最终增强:" + jp.getSignature().getName() + "方法结束执行。"); }

    Application.xml配置文件:

    <!--将afterLogger()方法定义为最终增强并引用到pointCut切入点--> <aop:after method="afterLogger" pointcut-ref="pointcut"/>

    环绕增强

    环绕增强:目标方法前后都可织入增强处理,功能最强大的增强处理 ​ 可获取或修改目标方法的参数,返回值,可对他进行异常处理,甚至可以决定目标方法是否执行。

    //环绕增强 //目标方法前后都可织入增强处理 //功能最强大的增强处理 //可获取或修改目标方法的参数,返回值,可对他进行异常处理,甚至可以决定目标方法是否执行。 public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable { log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs())); try { Object result = jp.proceed(); log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result); return result; } catch (Throwable e) { log.error("环绕增强:"+jp.getSignature().getName() + "方法发生异常:" + e); throw e; } finally { log.info("环绕增强:"+jp.getSignature().getName() + "方法结束执行。"); } }

    Application.xml配制文件:

    <!--将aroundLogger()方法定义为环绕增强并引用pointcut切入点--> <aop:around method="aroundLogger" pointcut-ref="pointcut"/>

    常用增强处理类型

    增强处理类型特点Before前置增强处理,在目标方法前织入增强处理AfterReturning后置增强处理,在目标方法正常执行(不出现异常)后织入增强处理AfterThrowing异常增强处理,在目标方法抛出异常后织入增强处理After最终增强处理,不论方法是否抛出异常,都会在目标方法最后织入增强处理Around环绕增强处理,在目标方法的前后都可以织入增强处理

    编写AOP增强类的方法

    public class UserServiceLogger { private static Logger log = Logger.getLogger(UserServiceLogger.class); //定义切入点 @Pointcut("execution(* org.westos.demo.service.*.*(..))") public void pointcut(){} /** * 切入点 规则 * public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。 * public void *(entity.User): “*”表示匹配所有方法名。 * public void addNewUser(..): “..”表示匹配所有参数个数和类型。 * * com.service.*.*(..):匹配com.service包下所有类的所有方法。 * * com.service..*.*(..):匹配com.service包及其子包下所有类的所有方法 */ //前置增强 //JoinPoint:目标方法的类名,方法名,参数列表 @Before("pointcut()") public void before(JoinPoint jp) { log.info("前置增强:" + "调用 " + jp.getTarget() + " 的 " + jp.getSignature(). getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs())); } //后置增强 //JoinPoint:目标方法的类名,方法名 参数列表 //result:获取目标,方法的返回值 @AfterReturning(pointcut = "pointcut()",returning = "result") public void afterReturning(JoinPoint jp, Object result) { log.info("后置增强:" + "调用 " + jp.getTarget() + " 的 " + jp.getSignature(). getName() + " 方法。方法返回值:" + result); } //异常增强:afterThrowing //运行时异常:RuntimeException public void afterThrowing(JoinPoint jp, RuntimeException e) { log.error("异常抛出增强:" + jp.getSignature().getName() + "方法发生异常:" + e); } //最终增强 //无论方法是否抛出,都会在目标方法最后织入增强处理,即:该增强都会得到执行。 //类似于异常处理机制中的finally块的作用,一般用于释放资源。 @After("execution(* org.westos.demo.service.*.*(..))") public void afterLogger(JoinPoint jp) { log.info("最终增强:" + jp.getSignature().getName() + "方法结束执行。"); } //环绕增强 //目标方法前后都可织入增强处理 //功能最强大的增强处理 //可获取或修改目标方法的参数,返回值,可对他进行异常处理,甚至可以决定目标方法是否执行。 @Around("execution(* org.westos.demo.service.*.*(..))") public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable { log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs())); try { Object result = jp.proceed(); log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result); return result; } catch (Throwable e) { log.error("环绕增强:"+jp.getSignature().getName() + "方法发生异常:" + e); throw e; } finally { log.info("环绕增强:"+jp.getSignature().getName() + "方法结束执行。"); } } }

    Application.xml配制文件

    <!--切面--> <aop:config> <!--切入点:PointCut--> <!--expression="execution(访问修饰符 返回值类型 方法名( 包名.类名( 参数 ) ))" --> <!-- .. 任何参数 --> <!-- org.westos.demo.service.*.* 第一个* 表示所有类 第二个*所有方法 --> <aop:pointcut id="pointcut" expression="execution(* org.westos.demo.service.*.*(..))"/> <!-- 可以有很多个增强类 使用哪一个增强类 增强取决于 aop:aspect ref ="bean id"--> <aop:aspect ref="userServiceLogger"> <!-- aop:before: 固定格式 前置增强 --> <!-- method 方法名称 (来自增强类) --> <!-- pointcut-ref 切入点名称 aop:pointcut id="pointcut" --> <aop:before method="before" pointcut-ref="pointcut"></aop:before> <!-- aop:after-returning: 固定格式 后置增强 --> <!-- method 方法名称 (来自增强类) --> <!-- pointcut-ref 切入点名称 aop:pointcut id="pointcut" --> <!-- returning 有返回值参数 (来自增强类) --> <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/> <!--aop:after-throwing:异常增强,在目标方法抛出异常时织入增强处理 异常抛出增强 e代表收集异常信息的--> <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/> <!--将afterLogger()方法定义为最终增强并引用到pointCut切入点--> <aop:after method="afterLogger" pointcut-ref="pointcut"/> <!--将aroundLogger()方法定义为环绕增强并引用pointcut切入点--> <aop:around method="aroundLogger" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>

    测试类

    public class TestUser { @Test public void testA(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); int row = userService.addUser(new User("zhangsan", "张三", "123456")); System.out.println(row==1?"成功":"失败"); } }

    注解:

    @Repository(bean _ id属性) 用于注解DAO层

    @service(bean _ id属性) 用于注解Service层

    (下面两个要一起使用)

    @Autowired 用于按照类型注入

    @Qualifier(bean _ id)

    @Resource(name=“bean - id”) 用于按照名称注入

    @Component:用于标注通用业务,实现Bean组件的定义

    @value(“值”) 将固定的值注入到属性中

    @Scope(“值”) 将固定的值注入到属性中

    @Aspect:用于标注增强类

    扫描有注解的类,包

    增强注解: 注意(1):在Application.xml中添加如下: <!--开启 注解是 切面 启用对于@AspectJ注解的支持--> <aop:aspectj-autoproxy/> 注意(2):扫描包 需要扫描到增强类 <context:component-scan base-package="org.westos.demo"></context:component-scan> @Aspect 注解增强类 //定义切入点 @Pointcut("execution(*org.westos.demo.service.*.*(..))") public void pointcut(){} @Before("pointcut()") 前置增强 @Before("execution(* org.westos.demo.service.*.*(..))") 前置增强 @AfterReturning(pointcut="pointcut()",returning="result") 后置增强 returning="result" 返回值参数名称 @AfterThrowing(pointcut="pointcut()",throwing="e") 异常抛出增强 throwing="e",参数,异常类型,名称 @After("execution(* org.westos.demo.service.*.*(..))") 最终增强 @Around("execoutor(* org.westos.demo.service.*.*(..))") 环绕增强

    推荐使用注解开发

    (1)在Application.xml配置文件中,引入一个context约束

    <?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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> </beans>

    (2)配置扫描哪些包下的注解

    <!--扫描包--> <context:component-scan base-package="com.xk.demo.dao"></context:component-scan> <context:component-scan base-package="com.xk.demo.service"></context:component-scan>

    (3)进行注解的标记

    @Repository (bean的id):用于标注DAO层 @Service :用于标注业务层 下面两个要一起使用 @Autowired: 用于按照类型注入 @Qualifier

    (4)两种注入方式

    1.类型注入:

    dao层:

    @Repository("userDaoImpl")//这个类似于id属性,不能发生重名属性 public class UserDaoImpl implements UserDao { @Override public int addUser(User user) { System.out.println("UserDaoImpl >>>>>>addUser "); return 1; } @Override public int updateUser(User user) { System.out.println("UserDaoImpl >>>>>>updateUser "); return 1; } @Override public int deleteUser(String userID) { System.out.println("UserDaoImpl >>>>>>deleteUser "); return 1; } }

    service层:

    @Service("userService")//这个类似于id属性,不能发生重名属性。 public class UserServiceImpl implements UserService { //类型注入 /*@Autowired @Qualifier("userDaoImpl") 这两个要一块使用*/ @Resource(name = "userDaoImpl") private UserDao userDao; // 创建SET访问器 用于是spring 注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public int addUser(User user) { System.out.println("UserServiceImpl >>>>>>>>>>>addUser"); //这里我们手动设置一个异常抛出增强,强制 抛出异常 //if(true) //throw new RuntimeException("手动设置异常抛出增强测试"); return userDao.addUser(user); } @Override public int updateUser(User user) { System.out.println("UserServiceImpl >>>>>>>>>>>updateUser"); return userDao.updateUser(user); } @Override public int deleteUser(String userID) { System.out.println("UserServiceImpl >>>>>>>>>>>deleteUser"); return userDao.deleteUser(userID); } }

    测试结果: 名称注入:

    @Resource(name = “userDao2”) 用于按照名称进行注入

    UserServiceImpl.java

    @Service("userService")//这个类似于id属性,不能发生重名属性。 public class UserServiceImpl implements UserService { //类型注入 /*@Autowired @Qualifier("userDaoImpl") 这两个要一块使用*/ @Resource(name = "userDaoImpl") private UserDao userDao; // 创建SET访问器 用于是spring 注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public int addUser(User user) { System.out.println("UserServiceImpl >>>>>>>>>>>addUser"); //这里我们手动设置一个异常抛出增强,强制 抛出异常 //if(true) //throw new RuntimeException("手动设置异常抛出增强测试"); return userDao.addUser(user); } @Override public int updateUser(User user) { System.out.println("UserServiceImpl >>>>>>>>>>>updateUser"); return userDao.updateUser(user); } @Override public int deleteUser(String userID) { System.out.println("UserServiceImpl >>>>>>>>>>>deleteUser"); return userDao.deleteUser(userID); } }

    通用型注解:

    @Component 用于标注通用业务,实现bean的定义

    @Value(“admin”) 用于将固定的值注入到属性中

    User.java

    @Component("user")//用于注入通用标注的业务 //@Scope("prototype") 作用域 public class User { @Value("admin") private String userCode; @Value("张三") private String userName; @Value("123456") private String userPwd; public User() { } /* public User(String userCode, String userName) { this.userCode = userCode; this.userName = userName; }*/ public User(String userCode, String userName, String userPwd) { this.userCode = userCode; this.userName = userName; this.userPwd = userPwd; } public String getUserCode() { return userCode; } public void setUserCode(String userCode) { this.userCode = userCode; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } }

    测试:

    public class TestUser { @Test public void testB(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml"); /*转换为 接口 接口 接口 UserService*/ User user = (User) applicationContext.getBean("user"); System.out.println(user.getUserName()); System.out.println(user.getUserCode()); System.out.println(user.getUserPwd()); } }

    作用域注解

    scop : 设置bean的作用域 singleton:默认值 在spirng IOC 容器仅存在一个bean ,单例模式 prototype: 每次从容器中调用Bean时 ,都返回一个新的实例 例如 new xxxBean(); request: 每次HTTP请求 都会创建一个新的Bean,作用域仅限于WEBApplicationContext环境 session:同一个HTTP Session共享一个Bean,不同的Session使用不同的Bean,作用域仅限于WEBApplicationContext环境 global-session:一般用于Portlet应用环境,作用域仅限于WEBApplicationContext环境 @Scope("prototype") //作用域 public class User { @Value("admin") private String userCode; @Value("张三") private String userName; @Value("123456") private String userPwd; public User() { } /* public User(String userCode, String userName) { this.userCode = userCode; this.userName = userName; }*/ public User(String userCode, String userName, String userPwd) { this.userCode = userCode; this.userName = userName; this.userPwd = userPwd; } public String getUserCode() { return userCode; } public void setUserCode(String userCode) { this.userCode = userCode; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } }

    测试:

    @Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user"); User user1 = (User) context.getBean("user"); User user2 = (User) context.getBean("user"); User user3 = (User) context.getBean("user"); System.out.println(user); System.out.println(user.getUserCode()); System.out.println(user.getUserName()); System.out.println(user.getUserPwd()); }

    用户标注增强类:

    使用@AspectJ,首先要保证所用的JDK 是5.0或以上版本 其次,要开启注解式的面向切面

    UserServiceLogger.java

    @Aspect public class UserServiceLogger { private static Logger log = Logger.getLogger(UserServiceLogger.class); //定义切入点 @Pointcut("execution(* org.westos.demo.service.*.*(..))") public void pointcut(){} /** * 切入点 规则 * public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。 * public void *(entity.User): “*”表示匹配所有方法名。 * public void addNewUser(..): “..”表示匹配所有参数个数和类型。 * * com.service.*.*(..):匹配com.service包下所有类的所有方法。 * * com.service..*.*(..):匹配com.service包及其子包下所有类的所有方法 */ //前置增强 //JoinPoint:目标方法的类名,方法名,参数列表 @Before("pointcut()") public void before(JoinPoint jp) { log.info("前置增强:" + "调用 " + jp.getTarget() + " 的 " + jp.getSignature(). getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs())); } //后置增强 //JoinPoint:目标方法的类名,方法名 参数列表 //result:获取目标,方法的返回值 @AfterReturning(pointcut = "pointcut()",returning = "result") public void afterReturning(JoinPoint jp, Object result) { log.info("后置增强:" + "调用 " + jp.getTarget() + " 的 " + jp.getSignature(). getName() + " 方法。方法返回值:" + result); } //异常增强:afterThrowing //运行时异常:RuntimeException public void afterThrowing(JoinPoint jp, RuntimeException e) { log.error("异常抛出增强:" + jp.getSignature().getName() + "方法发生异常:" + e); } //最终增强 //无论方法是否抛出,都会在目标方法最后织入增强处理,即:该增强都会得到执行。 //类似于异常处理机制中的finally块的作用,一般用于释放资源。 @After("execution(* org.westos.demo.service.*.*(..))") public void afterLogger(JoinPoint jp) { log.info("最终增强:" + jp.getSignature().getName() + "方法结束执行。"); } //环绕增强 //目标方法前后都可织入增强处理 //功能最强大的增强处理 //可获取或修改目标方法的参数,返回值,可对他进行异常处理,甚至可以决定目标方法是否执行。 @Around("execution(* org.westos.demo.service.*.*(..))") public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable { log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参:" + Arrays.toString(jp.getArgs())); try { Object result = jp.proceed(); log.info("环绕增强:调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值:" + result); return result; } catch (Throwable e) { log.error("环绕增强:"+jp.getSignature().getName() + "方法发生异常:" + e); throw e; } finally { log.info("环绕增强:"+jp.getSignature().getName() + "方法结束执行。"); } } }
    Processed: 0.020, SQL: 8