公司最近要求在某些程序出异常的时候,发封邮件至某个coder,用来及时检查问题所在,要求详细知道哪个类,哪个方法出的异常,出的什么异常等,而且不修改以前的程序代码!
于是想到了spring的AOP.想到了其中的ThrowsAdvice接口,这是用来再程序出了异常之后拦截,而后添加功能的.
本以为很简单,于是简单些了下测试类,
测试的业务类没有实现接口,就是一个java类,本身应用了spring的申明事务.步骤如下:
1.先写一个pojo的advice通知:
public class Advice {
public void throwing(Exception ex){
System.out.println("pojo的afterThrowing...exception:"+ex.getMessage());
}
}
2.spring配置文件,把通知应用到pointcut中:
<bean id="adviceBean" class="com.zhangwei.struts.Advice"></bean>
<!-- 利用spring AOP的配置元素定义一个通知 -->
<aop:config >
<!-- 引用刚才定义的一个纯粹的POJO切面Bean -->
<aop:aspect ref="adviceBean">
<!-- 定义一个命名切点,必点切点定义的重复,expression用于配置匹配规则,(返回类型 返回类.方法(参数设置) -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 方法跑出异常后通知 -->
<aop:after-throwing pointcut-ref="todo" method="throwing" throwing="ex"/>
</aop:aspect>
</aop:config>
之后运行,发现错了,原因在于我的测试业务类没有实现某一接口,因为事务管理用了AOP,我的advice又用了AOP,事务管理时我的业务类成了proxy,应用我的advice时,proxy无法类型转换至业务类,报错.后来又了解决方式,就是指定proxyTargetClass的值为true,强制使用cglib生成子类,代码如下:
<aop:config proxy-target-class="true">
<!-- 引用刚才定义的一个纯粹的POJO切面Bean -->
<aop:aspect ref="adviceBean">
<!-- 定义一个命名切点,必点切点定义的重复,expression用于配置匹配规则,(返回类型 返回类.方法(参数设置) -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 方法前通知 -->
<aop:after-throwing pointcut-ref="todo" method="throwing" throwing="ex"/>
</aop:aspect>
</aop:config>
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="login*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
但是这样做的后果就是拦截器重复拦截,因为2个AOP功能,2个子类,同时起作用,就拦截了2次.解决方案:把我的业务类换成接口,方法调用改成接口调用.
本以为可以了,但是发现advice的method,target参数无法得到,配置如下:
<aop:after-throwing pointcut-ref="todo" method="throwing" throwing="ex"/>
无法给通知传参,只能得到一个exception类型的参数,得不到method,target等参数,琢磨了2小时,没有解决,头昏脑胀!
休息一小时,继续琢磨,得到正确解决方式:
1.写一个依赖于spring的advice:
public class Advisor implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target,
Exception ex) {
System.out.println("传统经典aop的afterThrowing2...");
System.out.println("methodName:"+method.getName());
System.out.println("traget:"+target.getClass().getInterfaces()[0].getName());
}
}
2.重新写配置文件:
<!-- 定义一个依赖于spring的通知 -->
<bean id="advice" class="com.zhangwei.struts.Advisor"></bean>
<aop:config >
<!-- 定义AOP的切入点 -->
<aop:pointcut id="todo" expression="execution(* com.zhangwei.struts.Bo.*(..)) " />
<!-- 定义建议者,需要通知以及切入点2个元素 -->
<aop:advisor advice-ref="advice" pointcut-ref="todo"/>
</aop:config>
解决问题!
************************************************************************************************
可是由于公司项目业务层是java类,又不能修改以前的代码,只能采用链式加AOP的方式去做了:
<bean id="login" class="com.zhangwei.struts.BoLogin">
<property name="daoLogin">
<ref bean="daoLogin" />
</property>
</bean>
<!-- 定义一个依赖于spring的通知 -->
<bean id="advice" class="com.zhangwei.struts.Advisor"></bean>
<bean id="memberAopAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="*" />
<property name="advice" ref="advice" />
</bean>
<!-- 第一层代理 -->
<bean id="loginProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--启用CGLib,代理的不再是接口-->
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="target">
<ref bean="login"/>
</property>
<property name="interceptorNames">
<value>memberAopAdvisor</value>
</property>
</bean>
<!-- 第二层代理对第一层代理继续代理 -->
<bean id="boLogin"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--启用CGLib,代理的不再是接口-->
<property name="proxyTargetClass">
<value>true</value>
</property>
<property name="target">
<ref bean="loginProxy"/>
</property>
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="login*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
程序中最后调用"boLogin"这个spring Bean 就没有问题了.
Ok!解决!
分享到:
相关推荐
Spring的AOP框架就是基于这些接口构建的,这样开发者可以编写一次拦截器,就可以在多个AOP框架中复用。 这三个jar包在Spring AOP中的角色如下: 1. `aspectjrt.jar`:提供AspectJ的运行时支持,用于实现基于...
在这个例子中,`MyAspect`类定义了一个切面,`logBefore`方法作为前置通知在执行`com.example.service`包下的所有方法前运行,`scheduledTask`方法是一个定时任务,每5秒执行一次。 通过结合Spring AOP和定时任务,...
面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,旨在将横切关注点(crosscutting concerns)从业务逻辑代码中分离出来,以提高模块化。C++中的AOP理论探讨了如何在C++平台上实现面向切面编程,...
在IT行业中,AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它旨在提高软件的可维护性和可复用性,通过将关注点分离来简化代码结构。权限验证是软件系统中一个重要的安全机制,用于确保只有具有...
// 第一次调用 login.login(); // 第二次调用 login.login(); // 第三次调用 ``` 5. **配置文件**: ```xml <bean id="advice" class="org.nitpro.aop.before.LoginBeforeAdvice" /> ...
1. aopalliance-1.0.jar:这是一个非常基础的AOP库,定义了AOP的核心接口,如`org.aopalliance.intercept.MethodInterceptor`和`org.aopalliance.aop.Advice`,这些接口为不同的AOP框架提供了统一的交互方式。...
AOP通过定义切面(Aspect)、通知(Advice)、切入点(Pointcut)和织入(Weaving)等概念,使得我们可以编写一次代码,然后在多个位置应用,而无需在每个具体方法中重复这些通用逻辑。 AOP的四种配置方式主要包括...
AOP允许我们在不修改原有业务逻辑的情况下,将这些共性功能以一种模块化的方式插入到业务代码中,从而提高了代码的可复用性和可维护性。 首先,理解AOP的核心概念: 1. **切面(Aspect)**:切面是关注点的模块化,...
`MethodInvocation`接口则代表了对目标方法的一次调用,它包含了关于方法的信息,如方法名、参数等,以及调用的能力。通过实现这些接口,开发者可以创建自己的拦截器,实现在方法调用前后的扩展逻辑。 接下来,我们...
这样,我们可以编写一次切面代码,然后在多个类或方法中重复使用,从而提高代码的可复用性和可维护性。 **1.2 AOP的相关术语** - **切面(Aspect)**:切面是关注点的模块化,它包含了通知和切点。 - **通知...
本次分享的"一个简单aop分享.zip"可能包含了一次关于如何在Spring框架中使用AOP进行编程的讲解。 首先,理解AOP的基本概念非常重要。切面(Aspect)是关注点的模块化,它封装了跨越多个对象的行为或责任。通知...
在处理大量数据时,一次性加载所有数据不仅会消耗大量的内存,也可能导致用户界面响应变慢。因此,分页技术应运而生。在Java中,实现分页通常有以下几种方式: 1. 手动分页:开发者自行编写SQL查询,通过LIMIT和...
当用户再次尝试上传或下载时,系统会检查这些元数据,并从上一次停止的位置开始。这个过程可能需要服务器端存储文件的部分内容,并能识别和合并不同的部分。 3. **AOP(面向切面编程)**: AOP是Java中一种用于...
FastClickAop通常通过AOP来实现,当用户连续点击时,确保按钮在一定时间内只能响应一次点击事件,防止重复操作。 使用AspectJ与Kotlin结合实现AOP,主要步骤如下: 1. 引入AspectJ库:在项目build.gradle文件中...
通过AOP,我们可以把这些功能编写一次,然后在整个应用程序中跨多个对象和方法应用,而无需在每个具体的地方重复代码,从而实现了代码的解耦和模块化。 在Android中,我们可以使用第三方库如AspectJX或者Android ...
假设系统由一系列的BusinessObject所完成业务逻辑功能,系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。 Java代码 public interface BusinessInterface { public void ...
4. **AOP注解**:在AOP中,我们可以使用`@Aspect`注解定义一个切面,然后使用`@Before`、`@After`、`@Around`等通知来执行相应的操作。在这个场景下,我们可以在方法上添加自定义注解,比如`@UseDataSource("primary...
本资料包"spring-aop-4.2.6.RELEASE.zip"正是针对Spring AOP的一个重要版本,它与"spring-framework.zip"一同构成了强大的弹簧框架体系。开源项目的精神在此得以充分体现,为开发者提供了丰富的功能和高度的灵活性。...
力求获得一种简洁实用的方法实现IOC和AOP相结合的使用方式。 查阅了多个技术资料。经过多次测试,基本达到目的。 IOC使用微软的 Microsoft.Practices.Unity,AOP 使用微软企业库的 Microsoft.Practices.Enterprise...
5. **单例模式(Singleton)**:Spring AOP中的`SingletonTargetSource`保证了每个目标对象只被创建一次,实现了单例模式,确保在整个应用程序中只有一个共享的实例存在,提高了资源利用效率。 6. **适配器模式...