Spring 通过注解方式实现AOP切面编程

        Spring 切面编程的目的是实现代码的业务逻辑的解耦。切面编程用于诸如日志记录,事务处理,等非业务性的逻辑操作。目前Spring的Aop只能应用于方法层级上,无法在类、成员字段等层级上操作。以下是Srping的Aop编程分为注解方式和xml配置方式。以下过程详细说明了通过注解方式实现AOP编程的过程。
  • 第一步:自定义注解

/**
 * 定义自定义管理员注解
 *
 */
public @interface RoleAdmin { 
     String values() default "";

     String descript() defalut "自定义管理员注解";
}

  • 第二步:编写AOP切面类

/*声明为组件,让spring 自动管理*/
@Component
/*声明该类为切面bean*/
@Aspect
public class RequestInterceptor { 
        private final Logger logger = LoggerFactory.getLogger(RequestInterceptor.class); 

        /* 拦截管理员访问的请求,(定义切点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点)*/     
        @Pointcut("@annotation(com.frame.annotation.RoleAdmin)")
        public void adminRequired() {}

        /*定义前置advice,同时接受JoinPoint切入点对象,可以没有该参数
          在环绕通知里面proceedingJoinPoint参数是必须的,其他情况JoinPoint 并不是必须的
        */
        @Before("adminRequired()")
        public void adminCommon(JoinPoint point) {        
              HttpServletRequest request = getRequest();
        LoginUser user = (LoginUser) request.getSession().getAttribute(Constants.SESSION_USER_KEY);
        if ( user == null ) {
            setForward(request);
            throw new NoAdminException();
            //throw new NotLoginException();
        }
        if  ( user.getMemberType() != Constants.MEMBER_TYPE_ADMIN ) {
            throw new NoAdminException();
            //throw new NoAuthException();
        }
        String mac = (String)request.getSession().getAttribute(AdminUtil.ADMIN_MAC_ATTR_NAME);
        if(UtilString.isEmpty(mac)){
            throw new NoAdminException();
        }
        }
      
        private void setForward(HttpServletRequest request) {
               if ( "get".equalsIgnoreCase(request.getMethod()) ) {
                   String fw = request.getRequestURI().substring(request.getContextPath().length()+1);
                   String qs = request.getQueryString();
                   if ( ! UtilString.isEmpty(qs) ) {
                       fw += "?" + qs;
                   }

                   logger.debug("After login will forward to : {}", fw);
                   request.getSession().setAttribute(Constants.URL_FORWARD_KEY, fw);
                }
         } 

         /** * 在切面中获取http请求 * @return */ 
        private HttpServletRequest getRequest() { 
            return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 
        }
}
 

  • 第三步:在application.xml中配置aop代理

               需要在application.xml中添加AOP代理。AOP代理分为JDK代理和cglib代理

               如果配置proxy-target-class="true",则表示是cglib代理。如下:

	<!-- 激活自动代理功能 -->
       <aop:aspectj-autoproxy proxy-target-class="true"/>

               如果采用JDK代理,则配置如下:

       <aop:aspectj-autoproxy/>

  •  第四步: 定义切面的引入点

        /*在需要切面的方法上定义JoinCut点*/
        @RoleAdmin(descript="在这里定义")
        @ResponseBody
        @RequestMapping(value="admin/activity/updateComment")
        public boolean updateCommentIsDelete(HttpServletRequest request,CommentPlan commentPlan){
            return false;
        }

        切入点匹配多个连接点的两种方式

  • 通过@annotation精确切入到某个自定义标签中

       @Pointcut("@annotation(com.frame.annotation.RoleAdmin)")

  • 通过exrcution模糊匹配

       @Pointcut("execution(* cn.ysh.studio.spring.aop.service..*(..))")  

              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(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。

         AOP获取注解和Target对象

       /*定义前置advice*/
        @Before("execution(* cn.ysh.studio.spring.aop.service..*(..))&&@annotation(roleAdmin)") 
        public void adminCommon(JoinPoint point, RoleAdmin roleAdmin) {
            /*输出注解描述内容*/
            System.out.println(roleAdmin.descript());

            /*利用反射显示目标对象的相关信息*/  
            String targetName = joinPoint.getTarget().getClass().getName();    
       String methodName = joinPoint.getSignature().getName();    
       Object[] arguments = joinPoint.getArgs();    
       Class targetClass = Class.forName(targetName);    
       Method[] methods = targetClass.getMethods();    
       String description = "";
      for(Method method : methods) {    
      if(method.getName().equals(methodName)) {    
           Class[] clazzs = method.getParameterTypes();    
         if (clazzs.length == arguments.length) {   
             description = method.getAnnotation(SystemControllerLog.class).description();    
           break;    
         }    
       }  
        }
            

 

         在Spring中,任何通知(Advice)方法都可以将第一个参数定义为 org.aspectj.lang.JoinPoint类型用以接受当前连接点对象。JoinPoint接口提供了一系列有用的方法, 比如 getArgs() (返回方法参数)、getThis() (返回代理对象)、getTarget() (返回目标)、getSignature() (返回正在被通知的方法相关信息)和 toString() (打印出正在被通知的方法的有用信息)。

        1、如果要设置多个切点,则使用||进行拼接

    @Pointcut("execution(* aop.annotation.*.*(..))|| execution(*com.action.admin.*.*update*(..))")

        2、环绕通知的方法中一定要有ProceedingJoinPoint 参数,与Filter中的doFilter方法类似)
    @Around("execution(* aop.annotation.*.*(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws{

    }

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值