先说注解,使用注解配置Spring AOP总体分为两步,第一步是在xml文件中声明激活自动扫描组件功能,同时激活自动代理功能(同时在xml中添加一个UserService的普通服务层组件,来测试AOP的注解功能):
<xml version="10" encoding="UTF-8">
<beans xmlns=">
第二步是为Aspect切面类添加注解:
package cnyshstudiospringaopaspect;
import orgapachecommonsloggingLog;
import orgapachecommonsloggingLogFactory;
import orgaspectjlangJoinPoint;
import orgaspectjlangProceedingJoinPoint;
import orgaspectjlangannotationAfter;
import orgaspectjlangannotationAfterReturning;
import orgaspectjlangannotationAfterThrowing;
import orgaspectjlangannotationAround;
import orgaspectjlangannotationAspect;
import orgaspectjlangannotationBefore;
import orgaspectjlangannotationPointcut;
import orgspringframeworkstereotypeComponent;
/
系统服务组件Aspect切面Bean
@author Shenghany
@date 2013-5-28
/
//声明这是一个组件
@Component
//声明这是一个切面Bean
@Aspect
public class ServiceAspect {
private final static Log log = LogFactorygetLog(ServiceAspectclass);
//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
@Pointcut("execution( cnyshstudiospringaopservice())")
public void aspect(){ }
/
配置前置通知,使用在方法aspect()上注册的切入点
同时接受JoinPoint切入点对象,可以没有该参数
/
@Before("aspect()")
public void before(JoinPoint joinPoint){
if(logisInfoEnabled()){
loginfo("before " + joinPoint);
}
}
//配置后置通知,使用在方法aspect()上注册的切入点
@After("aspect()")
public void after(JoinPoint joinPoint){
if(logisInfoEnabled()){
loginfo("after " + joinPoint);
}
}
//配置环绕通知,使用在方法aspect()上注册的切入点
@Around("aspect()")
public void around(JoinPoint joinPoint){
long start = SystemcurrentTimeMillis();
try {
((ProceedingJoinPoint) joinPoint)proceed();
long end = SystemcurrentTimeMillis();
if(logisInfoEnabled()){
loginfo("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
}
} catch (Throwable e) {
long end = SystemcurrentTimeMillis();
if(logisInfoEnabled()){
loginfo("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + egetMessage());
}
}
}
//配置后置返回通知,使用在方法aspect()上注册的切入点
@AfterReturning("aspect()")
public void afterReturn(JoinPoint joinPoint){
if(logisInfoEnabled()){
loginfo("afterReturn " + joinPoint);
}
}
//配置抛出异常后通知,使用在方法aspect()上注册的切入点
@AfterThrowing(pointcut="aspect()", throwing="ex")
public void afterThrow(JoinPoint joinPoint, Exception ex){
if(logisInfoEnabled()){
loginfo("afterThrow " + joinPoint + "\t" + exgetMessage());
}
}
}
测试代码:
package cnyshstudiospringaop;
import orgapachecommonsloggingLog;
import orgapachecommonsloggingLogFactory;
import orgspringframeworkcontextApplicationContext;
import orgspringframeworkcontextsupportClassPathXmlApplicationContext;
import cnyshstudiospringaopserviceUserService;
import cnyshstudiospringmvcbeanUser;
/
Spring AOP测试
@author Shenghany
@date 2013-5-28
/
public class Tester {
private final static Log log = LogFactorygetLog(Testerclass);
public static void main(String[] args) {
//启动Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContextxml");
//获取service组件
UserService service = (UserService) contextgetBean("userService");
//以普通的方式调用UserService对象的三个方法
User user = serviceget(1L);
servicesave(user);
try {
servicedelete(1L);
} catch (Exception e) {
if(logisWarnEnabled()){
logwarn("Delete user : " + egetMessage());
}
}
}
}
控制台输出如下:
INFO [springaopaspectServiceAspect:40] before execution(User cnyshstudiospringaopserviceUserServiceget(long))
INFO [springaopserviceUserService:19] getUser method
INFO [springaopaspectServiceAspect:60] around execution(User cnyshstudiospringaopserviceUserServiceget(long)) Use time : 42 ms!
INFO [springaopaspectServiceAspect:48] after execution(User cnyshstudiospringaopserviceUserServiceget(long))
INFO [springaopaspectServiceAspect:74] afterReturn execution(User cnyshstudiospringaopserviceUserServiceget(long))
INFO [springaopaspectServiceAspect:40] before execution(void cnyshstudiospringaopserviceUserServicesave(User))
INFO [springaopserviceUserService:26] saveUser method
INFO [springaopaspectServiceAspect:60] around execution(void cnyshstudiospringaopserviceUserServicesave(User)) Use time : 2 ms!
INFO [springaopaspectServiceAspect:48] after execution(void cnyshstudiospringaopserviceUserServicesave(User))
INFO [springaopaspectServiceAspect:74] afterReturn execution(void cnyshstudiospringaopserviceUserServicesave(User))
INFO [springaopaspectServiceAspect:40] before execution(boolean cnyshstudiospringaopserviceUserServicedelete(long))
INFO [springaopserviceUserService:32] delete method
INFO [springaopaspectServiceAspect:65] around execution(boolean cnyshstudiospringaopserviceUserServicedelete(long)) Use time : 5 ms with exception : spring aop ThrowAdvice演示
INFO [springaopaspectServiceAspect:48] after execution(boolean cnyshstudiospringaopserviceUserServicedelete(long))
INFO [springaopaspectServiceAspect:74] afterReturn execution(boolean cnyshstudiospringaopserviceUserServicedelete(long))
WARN [studiospringaopTester:32] Delete user : Null return value from advice does not match primitive return type for: public boolean cnyshstudiospringaopserviceUserServicedelete(long) throws javalangException
可以看到,正如我们预期的那样,虽然我们并没有对UserSerivce类包括其调用方式做任何改变,但是Spring仍然拦截到了其中方法的调用,或许这正是AOP的魔力所在。
再简单说一下xml配置方式,其实也一样简单:
<xml version="10" encoding="UTF-8">
<beans xmlns=">
个人觉得不如注解灵活和强大,你可以不同意这个观点,但是不知道如下的代码会不会让你的想法有所改善:
//配置前置通知,拦截返回值为cnyshstudiospringmvcbeanUser的方法
@Before("execution(cnyshstudiospringmvcbeanUser cnyshstudiospringaopservice())")
public void beforeReturnUser(JoinPoint joinPoint){
if(logisInfoEnabled()){
loginfo("beforeReturnUser " + joinPoint);
}
}
//配置前置通知,拦截参数为cnyshstudiospringmvcbeanUser的方法
@Before("execution( cnyshstudiospringaopservice(cnyshstudiospringmvcbeanUser))")
public void beforeArgUser(JoinPoint joinPoint){
if(logisInfoEnabled()){
loginfo("beforeArgUser " + joinPoint);
}
}
//配置前置通知,拦截含有long类型参数的方法,并将参数值注入到当前方法的形参id中
@Before("aspect()&&args(id)")
public void beforeArgId(JoinPoint joinPoint, long id){
if(logisInfoEnabled()){
loginfo("beforeArgId " + joinPoint + "\tID:" + id);
}
}
附上UserService的代码(其实很简单):
package cnyshstudiospringaopservice;
import orgapachecommonsloggingLog;
import orgapachecommonsloggingLogFactory;
import cnyshstudiospringmvcbeanUser;
/
用户服务模型
@author Shenghany
@date 2013-5-28
/
public class UserService {
private final static Log log = LogFactorygetLog(UserServiceclass);
public User get(long id){
if(logisInfoEnabled()){
loginfo("getUser method ");
}
return new User();
}
public void save(User user){
if(logisInfoEnabled()){
loginfo("saveUser method ");
}
}
public boolean delete(long id) throws Exception{
if(logisInfoEnabled()){
loginfo("delete method ");
throw new Exception("spring aop ThrowAdvice演示");
}
return false;
}
}
应该说学习Spring AOP有两个难点,第一点在于理解AOP的理念和相关概念,第二点在于灵活掌握和使用切入点表达式。概念的理解通常不在一朝一夕,慢慢浸泡的时间长了,自然就明白了,下面我们简单地介绍一下切入点表达式的配置规则吧。
通常情况下,表达式中使用”execution“就可以满足大部分的要求。表达式格式如下:
execution(modifiers-pattern ret-type-pattern declaring-type-pattern name-pattern(param-pattern) throws-pattern)
modifiers-pattern:方法的 *** 作权限
ret-type-pattern:返回值
declaring-type-pattern:方法所在的包
name-pattern:方法名
parm-pattern:参数名
throws-pattern:异常
其中,除ret-type-pattern和name-pattern之外,其他都是可选的。上例中,execution( comspringservice())表示comspringservice包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。
最后说一下通知参数
可以通过args来绑定参数,这样就可以在通知(Advice)中访问具体参数了。例如,<aop:aspect>配置如下:
<aop:config>
<aop:aspect id="TestAspect" ref="aspectBean">
<aop:pointcut id="businessService"
expression="execution( comspringservice(String,)) and args(msg,)" />
<aop:after pointcut-ref="businessService" method="doAfter"/>
</aop:aspect>
</aop:config>上面的代码args(msg,)是指将切入点方法上的第一个String类型参数添加到参数名为msg的通知的入参上,这样就可以直接使用该参数啦。
全称也不说了,字面意思就是面向方面编程。举一个最普遍的例子,就是如果我们代码需要做日志的话,那么在没有AOP的时候,我们的代码可能就是这样:
public class A{
public void methodA(){
do log;
bmethodB();
}
}
这里methodA()中的做日志并不是方法本身的逻辑功能,而是一个附属功能,因此,我们需要把它分离出去。怎么分离,就是AOP要做的事情,简单来说,就是系统在调用者不知情的情况下,为我们的类A增加了一个代理类,她把我们的类A包装了起来,像这样:
public class AP extends A{
A a;
public void methodA(){
do log;
amethodA():
}
}
public class A{
public void methodA(){
bmethodB();
}
}
于是,当我们以为自己在调用A的methodA()方法时,实际调用的将是AP中的methodA(),于是就可以把做日志的功能从原有的methodA()中分离了出去。所以,AOP要做的就是在用户不知道的情况下,将我们的调用点包裹了起来,从而把原来的功能进行了分离。
@RequestMapping(value = "/login", method = RequestMethodGET)
public ModelAndView myMethod(>
以上就是关于spring中aop全注解时配置类怎么写全部的内容,包括:spring中aop全注解时配置类怎么写、请举例对比说明什么是AOP、aop怎么获取springmvc controller中的requestmapping等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)