精华内容
下载资源
问答
  • SpringBoot/MVC通过切面获取注解
    2021-03-22 16:58:49

    本文以MybatisPlus的多数据源切换注解@DS为例

    1. 项目背景介绍:
      1. SpringMVC项目迁移到SpirngCloud架构
      2. 老项目按mapper.java目录进行多数据源切换,新项目以@DS("指定数据源")注解进行切换
      3. 切面中逻辑需要同时兼容原因目录切换和注解切换
    2. 实现重点:获取注解值
    3. 代码:
    <!--多数据源依赖,DB依赖请自行添加-->
    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>

     

    类介绍:
    DataBaseAspect.java(切面)
    DataSourceContextHolder.java(DS指定)
    DBTypeEnum.java(DS枚举值)
    DynamicDataSource.java(SpringBoot切换DS)
    MybatisPlusConfig.java(配置DS对象)
    package com.xxl.config;
    
    import com.baomidou.dynamic.datasource.annotation.DS;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    @Order(-1)
    public class DataBaseAspect {
    
    
        /**
         * 使用第一个数据源的路径
         */
        @Pointcut("execution(* com.xxl.mapper.master.*.*(..))")
        public void dbPointCut() {}
    
        /**
         * 使用第二个数据源的路径
         */
        @Pointcut("execution(* com.xxl.mapper.read.*.*(..))")
        public void dbPointCut2() {}
    
        @Before("dbPointCut()")
        public void beforeSwitchDS(JoinPoint point) {
            DataSourceContextHolder.setDbType(DBTypeEnum.MASTER);
        }
    
        @Before("dbPointCut2()")
        public void change2(JoinPoint point) {
            DataSourceContextHolder.setDbType(DBTypeEnum.READ);
        }
    
        @Before("@annotation(com.baomidou.dynamic.datasource.annotation.DS)&&@annotation(ds)")
        public void mybatisPlusDS(JoinPoint point,DS ds) {
            DataSourceContextHolder.setDbType(ds.value());
        }
    
        @After("dbPointCut()")
        public void afterSwitchDS(JoinPoint point) {
            DataSourceContextHolder.clearDbType();
        }
    }
    
    
    package com.xxl.config;
    
    public class DataSourceContextHolder {
        private final static ThreadLocal contextHolder = new ThreadLocal<>(); //实际上就是开启多个线程,每个线程进行初始化一个数据源
        /**
         * 设置数据源
         * @param dbTypeEnum
         */
        public static void setDbType(DBTypeEnum dbTypeEnum) {
            contextHolder.set(dbTypeEnum.getValue());
        }
        public static void setDbType(String dbType) {
            contextHolder.set(dbType);
        }
    
        /**
         * 取得当前数据源
         * @return
         */
        public static String getDbType() {
            return (String) contextHolder.get();
        }
    
        /**
         * 清除上下文数据
         */
        public static void clearDbType() {
            contextHolder.remove();
        }
    }
    
    
    package com.xxl.config;
    
    import lombok.Getter;
    
    @Getter
    public enum DBTypeEnum {
    
        MASTER("master"), READ("read");
        private String value;
    
        DBTypeEnum(String value) {
            this.value = value;
        }
    
    }
    package com.xxl.config;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.getDbType();
        }
    }
    
    
    package com.xxl.config;
    
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.core.MybatisConfiguration;
    import com.baomidou.mybatisplus.core.config.GlobalConfig;
    import com.baomidou.mybatisplus.extension.MybatisMapWrapperFactory;
    import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
    import org.apache.ibatis.plugin.Interceptor;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.util.HashMap;
    import java.util.Map;
    
    @EnableTransactionManagement
    @Configuration
    @MapperScan(value = {"com.xxl.mapper.read.*,com.xxl.mapper.write.*,com.xxl.mapper.mp.*"})//指定对应的mapper路径
    public class MybatisPlusConfig {
        private static ApplicationContext applicationContext;
    
        //配置信息可以在被调用的时候写死
        @Autowired
        MybatisPlusNacosConfiguration mybatisPlusNacosConfiguration;
        /**
         * 分页插件
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
        @Bean(name = "db1")
        @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.master")
        public DataSource db1() {
            return new DruidDataSource();
        }
    
        @Bean(name = "db2")
        @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.read")
        public DataSource db2() {
            return new DruidDataSource();
        }
    
        /**
         * 动态数据源配置
         *
         * @return
         */
        @Bean(name = "multipleDataSource")
        @Primary
        public DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
                                             @Qualifier("db2") DataSource db2) {
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DBTypeEnum.MASTER.getValue(), db1);
            targetDataSources.put(DBTypeEnum.READ.getValue(), db2);
            dynamicDataSource.setTargetDataSources(targetDataSources);
            // 程序默认数据源,根据程序调用数据源频次,把常调用的数据源作为默认
            dynamicDataSource.setDefaultTargetDataSource(db1);
            return dynamicDataSource;
        }
    
        @Bean("sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
            sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2()));
            sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/*/*.xml"));
            sqlSessionFactory.setPlugins(new Interceptor[]{paginationInterceptor()});
            /**
             * Mybatis配置
             */
            MybatisConfiguration configuration = new MybatisConfiguration();
            configuration.setMapUnderscoreToCamelCase(mybatisPlusNacosConfiguration.getMapUnderscore2CamelCase());
            configuration.setCallSettersOnNulls(mybatisPlusNacosConfiguration.getCallSettersOnNulls());
            configuration.setCacheEnabled(false);
            // 数据库查询结果驼峰式返回
            sqlSessionFactory.setObjectWrapperFactory(new MybatisMapWrapperFactory());
            // 添加分页功能
            sqlSessionFactory.setPlugins(new Interceptor[]{paginationInterceptor()});
    
            GlobalConfig globalConfig = new GlobalConfig();
            globalConfig.setBanner(mybatisPlusNacosConfiguration.getBanner());
            GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
    
            dbConfig.setIdType(IdType.valueOf(mybatisPlusNacosConfiguration.getIdType()));
            globalConfig.setDbConfig(dbConfig);
    
            configuration.setGlobalConfig(globalConfig);
    
            sqlSessionFactory.setConfiguration(configuration);
            sqlSessionFactory.setGlobalConfig(globalConfig);
            return sqlSessionFactory.getObject();
        }
    
        @Bean(name = "multipleTransactionManager")
        @Primary
        public DataSourceTransactionManager multipleTransactionManager(@Qualifier("multipleDataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
    }
    
    

     

    更多相关内容
  • @Pointcut("@annotation... public void doLog() { } @Around("doLog()") public Object doLogAround(ProceedingJoinPoint joinPoint) throws Throwable{ //目的:获取切入点方法上自定义RequiredLog注解
    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
        public void doLog() {
        }
    
        @Around("doLog()")
        public Object doLogAround(ProceedingJoinPoint joinPoint)
                throws Throwable{
        
            //目的:获取切入点方法上自定义RequiredLog注解中operation属性值
            
            //1.1获取目标对象对应的字节码对象
            Class<?> targetCls=joinPoint.getTarget().getClass();
            
            
            //1.2获取目标方法对象
            
            //1.2.1 获取方法签名信息从而获取方法名和参数类型
            Signature signature=joinPoint.getSignature();
            
            //1.2.1.1将方法签名强转成MethodSignature类型,方便调用
            MethodSignature ms= (MethodSignature)signature;
            
            //1.2.2通过字节码对象以及方法签名获取目标方法对象
            Method targetMethod=targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
            
            
            //1.3获取目标方法对象上注解中的属性值
            
            //1.2.3 获取方法上的自定义requiredLog注解
            RequiredLog requiredLog=targetMethod.getAnnotation(RequiredLog.class);
            
            //1.2.4 获取自定义注解中operation属性的值
            String operation=requiredLog.operation();
            
            return null;
            }
    

    切面执行顺序

    切面的优先级需要借助@Order注解进行描述,数字越小优先级越高,默认优先级比较低。
    例如:定义日志切面并指定优先级。

    @Order(1)
    @Aspect
    @Componentpublic class SysLogAspect {...}
    

    定义缓存切面并指定优先级:

    @Order(2)
    @Aspect
    @Componentpublic class SysCacheAspect{...}
    

    通知类型

    Spring框架AOP模块定义通知类型,有如下几种:

    • @Around (优先级最高的通知,可以在目标方法执行之前,之后灵活进行业务拓展.)
    • @Before (目标方法执行之前调用)
    • @AfterReturning (目标方法正常结束时执行)
    • @AfterThrowing (目标方法异常结束时执行)
    • @After (目标方法结束时执行,正常结束和异常结束它都会执行)
      在这里插入图片描述
      说明:当多个切面作用于同一个目标对象方法时,这些切面会构建成一个切面链,类似过滤器链、拦截器链,其执行分析如图所示:
      在这里插入图片描述
    展开全文
  • } /** * 切面开始 */ @Before("api()&& @annotation(apiOperation)") public void doBefore(JoinPoint joinPoint, ApiOperation apiOperation) throws Throwable { // 如果你想获取其他注解可以使用一下方法获取,...
    1. controller代码
        @ApiOperation(value = "检查是否有兑换次数", response = Boolean.class)
        @ApiImplicitParam(name = "userId", value = "用户id", required = true)
        @GetMapping("/checkExchange")
        public R<Boolean> checkExchange(Long userId) {
            return emptyBottleOrderService.checkExchange(userId);
        }
    
    1. 切面代码 @annotation(apiOperation)的apiOperation对应的是方法的参数
    package com.ruoyi.framework.aspectj;
    
    import cn.hutool.json.JSONUtil;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    
    /**
     * api注解入参和出参切面
     *
     * @author gideon
     * @date 2022/3/5
     */
    @Slf4j
    @Aspect
    @Component
    public class ApiLogAspect {
    
        /**
         * 注解切面
         */
        @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
        public void api() {
        }
    
        /**
         * 切面执行
         */
        @Around("api()&& @annotation(apiOperation)")
        public Object doAround(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) throws Throwable {
            long startTime = System.currentTimeMillis();
            Object proceed = joinPoint.proceed();
            log.info(apiOperation.value() + ":结束:耗时{}毫秒:返回值:{}。", System.currentTimeMillis() - startTime, JSONUtil.toJsonStr(proceed));
            return proceed;
        }
    
        /**
         * 切面开始
         */
        @Before("api()&& @annotation(apiOperation)")
        public void doBefore(JoinPoint joinPoint, ApiOperation apiOperation) throws Throwable {
    //        如果你想获取其他注解可以使用一下方法获取,例如我的controller有@ApiImplicitParam
    /*        Class<?> targetCls = joinPoint.getTarget().getClass();
            //获取方法签名(通过此签名获取目标方法信息)
            MethodSignature ms = (MethodSignature) joinPoint.getSignature();
            //获取目标方法上的注解指定的操作名称
            Method targetMethod =
                    targetCls.getDeclaredMethod(
                            ms.getName(),
                            ms.getParameterTypes());
            ApiImplicitParam apiImplicitParam = targetMethod.getAnnotation(ApiImplicitParam.class);*/
            log.info(apiOperation.value() + ":开始:参数:{}。", JSONUtil.toJsonStr(joinPoint.getArgs()));
        }
    
        /**
         * 切面结束
         */
        @After("api()")
        public void doAfter() {
        }
    }
    
    1. 效果图
      在这里插入图片描述

    2. 转载请注明出处

    展开全文
  • spring中自定义注解(annotation)与AOP中获取注解.通过实例演示自定义注解。
  • 十、使用注解定义切面

    千次阅读 2021-03-09 06:57:51
    一、本课目标掌握使用注解实现AOP的方法二、使用注解定义切面2.1简介AspectJ面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译期提供代码的织入。@AspectJAspectJ5新增的功能,使用JDK5.0注解技术和正规...

    一、本课目标

    掌握使用注解实现AOP的方法

    二、使用注解定义切面

    2.1简介

    AspectJ

    面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译期提供代码的织入。

    @AspectJ

    AspectJ5新增的功能,使用JDK5.0注解技术和正规的AspectJ切点表达式语言描述切面(所以在使用@AspectJ的时候,要保证所用的JDK是5.0或者以上的版本)

    Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量

    利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名

    2.2示例

    需求:使用注解来实现日志切面

    分析:

    1、使用注解定义前置增强和后置增强实现日志功能

    2、编写Spring配置文件,完成切面织入

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    实体类:

    package entity;

    /**

    * 用户实体类

    */

    public class User implements java.io.Serializable {

    private Integer id; // 用户ID

    private String username; // 用户名

    private String password; // 密码

    private String email; // 电子邮件

    // getter & setter

    public Integer getId() {

    return id;

    }

    public void setId(Integer id) {

    this.id = id;

    }

    public String getUsername() {

    return username;

    }

    public void setUsername(String username) {

    this.username = username;

    }

    public String getPassword() {

    return password;

    }

    public void setPassword(String password) {

    this.password = password;

    }

    public String getEmail() {

    return email;

    }

    public void setEmail(String email) {

    this.email = email;

    }

    }

    增强类:

    package aop;

    import java.util.Arrays;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.Before;

    /**

    * 增强处理类

    * @author Administrator

    *

    */

    @Aspect

    public class UserServiceLogger {

    private static Logger log = Logger.getLogger(UserServiceLogger.class);

    @Before("execution(* service.UserService.*(..))")

    public void before(JoinPoint jp) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法参数" +

    Arrays.toString(jp.getArgs()));

    }

    public void afterReturning(JoinPoint jp, Object result) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法返回值" +

    result);

    }

    }

    dao层:

    package dao;

    import entity.User;

    /**

    * 增加DAO接口,定义了所需的持久化方法

    */

    public interface UserDao {

    public void save(User user);

    }

    package dao.impl;

    import org.springframework.stereotype.Repository;

    import dao.UserDao;

    import entity.User;

    /**

    * 用户DAO类,实现UserDao接口,负责User类的持久化操作

    */

    @Repository("userDao")

    public class UserDaoImpl implements UserDao {

    public void save(User user) {

    // 这里并未实现完整的数据库操作,仅为说明问题

    System.out.println("保存用户信息到数据库");

    }

    }

    service层:

    package service;

    import entity.User;

    /**

    * 用户业务接口,定义了所需的业务方法

    */

    public interface UserService {

    public void addNewUser(User user);

    }

    package service.impl;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.beans.factory.annotation.Qualifier;

    import org.springframework.stereotype.Service;

    import service.UserService;

    import dao.UserDao;

    import entity.User;

    /**

    * 用户业务类,实现对User功能的业务管理

    */

    @Service("userService")

    public class UserServiceImpl implements UserService {

    // 声明接口类型的引用,和具体实现类解耦合

    private UserDao dao;

    /* // 无参构造

    public UserServiceImpl() {

    }*/

    @Autowired

    // 指定装配的bean的名称

    public void setDao(@Qualifier("userDao")UserDao dao) {

    this.dao = dao;

    }

    /* // 用于为dao属性赋值的构造方法

    public UserServiceImpl(UserDao dao) {

    this.dao = dao;

    }*/

    public void addNewUser(User user) {

    // 调用用户DAO的方法保存用户信息

    dao.save(user);

    }

    }

    配置文件:

    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.2.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.2.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    测试类:

    package test;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    import service.UserService;

    import entity.User;

    public class Test {

    @org.junit.Test

    public void test() {

    // 使用ApplicationContext接口的实现类ClassPathXmlApplicationContext加载Spring配置文件

    ApplicationContext ctx = new ClassPathXmlApplicationContext(

    "applicationContext.xml");

    // 通过ApplicationContext接口的getBean()方法获取id或name为userService的Bean实例

    UserService service = (UserService) ctx.getBean("userService");

    User user = new User();

    user.setId(1);

    user.setUsername("test");

    user.setPassword("123456");

    user.setEmail("test@xxx.com");

    service.addNewUser(user);

    }

    }

    运行结果:

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    增加后置增强:

    package aop;

    import java.util.Arrays;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.AfterReturning;

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.Before;

    /**

    * 增强处理类

    * @author Administrator

    *

    */

    @Aspect

    public class UserServiceLogger {

    private static Logger log = Logger.getLogger(UserServiceLogger.class);

    @Before("execution(* service.UserService.*(..))")

    public void before(JoinPoint jp) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法参数" +

    Arrays.toString(jp.getArgs()));

    }

    @AfterReturning(pointcut="execution(* service.UserService.*(..))",

    returning="result")

    public void afterReturning(JoinPoint jp, Object result) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法返回值" +

    result);

    }

    }

    运行结果:

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    注:有时候同一个切入点要在很多地方用到,这时候我们要进行统一的定义,以方便我们的重用和维护。

    代码如下:

    package aop;

    import java.util.Arrays;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.AfterReturning;

    import org.aspectj.lang.annotation.Aspect;

    import org.aspectj.lang.annotation.Before;

    import org.aspectj.lang.annotation.Pointcut;

    /**

    * 增强处理类

    * @author Administrator

    *

    */

    @Aspect

    public class UserServiceLogger {

    private static Logger log = Logger.getLogger(UserServiceLogger.class);

    // 统一定义切入点,并定义该切入点的方法名

    @Pointcut("execution(* service.UserService.*(..))")

    public void pointcut() {}

    @Before("pointcut()")

    public void before(JoinPoint jp) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法参数" +

    Arrays.toString(jp.getArgs()));

    }

    @AfterReturning(pointcut="pointcut()",

    returning="result")

    public void afterReturning(JoinPoint jp, Object result) {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法返回值" +

    result);

    }

    }

    三、使用注解丁义珍增强

    需求说明:使用注解来定义异常抛出增强

    分析:

    使用@AfterThrowing注解定义异常抛出增强

    增强类:

    package aop;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.AfterThrowing;

    import org.aspectj.lang.annotation.Aspect;

    /**

    * 定义包含增强方法的JavaBean

    */

    @Aspect

    public class ErrorLogger {

    private static final Logger log = Logger.getLogger(ErrorLogger.class);

    @AfterThrowing(pointcut="execution(* service.UserService.*(..))",

    throwing="e")

    public void afterThrowing(JoinPoint jp, RuntimeException e) {

    log.error(jp.getSignature().getName() + " 方法发生异常:" + e);

    }

    }

    dao层

    package dao.impl;

    import org.springframework.stereotype.Repository;

    import dao.UserDao;

    import entity.User;

    /**

    * 用户DAO类,实现UserDao接口,负责User类的持久化操作

    */

    @Repository("userDao")

    public class UserDaoImpl implements UserDao {

    public void save(User user) {

    // 这里并未实现完整的数据库操作,仅为说明问题

    System.out.println("保存用户信息到数据库");

    throw new RuntimeException("为测试程序运行效果抛出的异常");

    }

    }

    配置文件:

    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.2.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.2.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    运行结果:

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    四、使用注解定义最终增强

    需求:使用注解来定义最终增强

    分析:使用@After注解定义最终增强

    增强类:

    package aop;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.annotation.After;

    import org.aspectj.lang.annotation.Aspect;

    @Aspect

    public class AfterLogger {

    private static Logger log = Logger.getLogger(AfterLogger.class);

    @After("execution(* service.UserService.*(..))")

    public void after(JoinPoint jp) {

    log.info(jp.getSignature().getName() + "方法结束了");

    }

    }

    配置文件:

    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.2.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.2.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    运行结果:

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    五、使用注解定义环绕增强

    需求说明:使用注解来定义环绕增强

    分析:使用@Around注解定义环绕增强

    增强类:

    package aop;

    import java.util.Arrays;

    import org.apache.log4j.Logger;

    import org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.ProceedingJoinPoint;

    import org.aspectj.lang.annotation.Around;

    import org.aspectj.lang.annotation.Aspect;

    @Aspect

    public class AroundLogger {

    private static Logger log = Logger.getLogger(AroundLogger.class);

    /**

    * 可以通过修改这个方法的返回值来修改目标方法的返回值

    * @param jp

    * @return

    * @throws Throwable

    */

    @Around("execution(* service.UserService.*(..))")

    public Object aroundLogger(ProceedingJoinPoint jp ) throws Throwable {

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法参数" +

    Arrays.toString(jp.getArgs()));

    Object result;

    try {

    result = jp.proceed();

    log.info("调用" + jp.getTarget() + "的" +

    jp.getSignature() + "方法,方法返回值" +

    result);

    return result;

    } catch (Throwable e) {

    log.error(jp.getSignature().getName() + " 方法发生异常:" + e);

    throw e;

    }finally {

    log.info(jp.getSignature().getName() + " 方法结束执行。");

    }

    }

    }

    配置文件:

    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.2.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context-3.2.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    运行结果:

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    六、小结

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    1329dfcb5c15?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    image.png

    展开全文
  • } @Around("aspectForPub()") public void logRecored(ProceedingJoinPoint joinPoint) { //swagger上的注解 try { Long start=System.currentTimeMillis(); Api a= (Api) (joinPoint.getSignature()....
  • AOP中获取自定义注解属性

    万次阅读 2018-06-05 15:39:35
    自定义注解@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface SystemLog { public String description() default ""; }用在方法上@ResponseBody @ValidRequestBody @...
  • 可能标题描述的不太清楚,请看下图: ![图片说明](https://img-ask.csdn.net/upload/202007/20/1595180589_804017.png) 我代码写到这个地步了: ![图片说明]...
  • 切面注解@Aspect

    2022-02-18 14:18:27
    @AfterReturning 切点方法返回后执行 @AfterThrowing 切点方法抛异常执行 @Around 属于环绕增强,能控制切点执行前,执行后,,用这个注解后,程序抛异常,会影响@AfterThrowing这个注解 第一步,配置切面 import org...
  • 6. 切面 package com.wdletu.log.aspect; import com.wdletu.core.exception.ServiceException; import com.wdletu.core.util.MapBean; import com.wdletu.core.util.StringUtil; import ...
  • 本文实现了,自定义个注解,用来标注切入点,就是说,你想让哪些个方法执行切面的方法,只需要在这些方法上面,添加自定义注解,然后,就可以执行切面的advice啦。 我们在切面可以拿到: 1,当前执行方法的参数。 2...
  • AOP组合使用切面和自定义注解

    千次阅读 2018-09-03 15:48:44
    添加切面依赖 &lt;dependency&gt; &lt;groupId&gt;org.aspectj&lt;/groupId&gt; &lt;artifactId&gt;aspectjrt&lt;/artifactId&gt; &lt;version&gt;1.8.5&...
  • Spring切面中实现自定义注解

    千次阅读 2019-06-06 11:23:16
    1.首先写出一个自定义注解。 package com.salong.aspect.test; import java.lang.annotation.*; @Target(ElementType.METHOD) @Documented @Retention(RetentionPolicy.RUNTIME) public @interface Login { ...
  • SpringBoot,AOP切面实现日志记录,自定义注解,注解属性动态传参 项目需求: 需要记录用户的操作具体的方法,记录当前具体操作的是哪一条数据信息,作为参数也一并保存起来。 如:更新数据,IP,电脑号,调用方法,...
  • * 切面获取的值就是cat.name的值,这里必须以root.开头,表示获取入参的属性值。 * */ @AnnotationDemo(channel="#root.name") public String methoDemo(Cat cat) { // todo 业务代码 }
  • Java Springboot切面+注解实现数据脱敏1. 业务概述2. 设计编码2.1 脱敏类型枚举2.2 脱敏注解2.3 脱敏工具类2.4 统一拦截器2.5...通过切面获取指定脱敏类型,实现将数据统一脱敏返回。 2. 设计编码 2.1 脱敏类型枚举 pac
  • 自定义一个注解并实现注解返回后处理逻辑功能 自定义一个注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CommunityOperation { /** * 主键 */ String ...
  • 切点为注解注释的地方时,获取自定义注解。
  • 先了解切面和自定义注解的基本概念和使用 一、AOP简介 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是...
  • Springboot 自定义注解切面

    千次阅读 2019-06-08 12:16:08
    本文实现的是使用自定义注解作为切入点。 1、创建springboot工程,引入依赖 本次任务实例主要引入以下两个依赖即可。 <dependencies> <dependency> <groupId>org.springframework.boot</...
  • 1、写一个切面 @Aspect @Component public class LogInfoAspect { @Pointcut(value = "@annotation(com.main.entity.annotation.LogInfo)") public void LogInfoAspect(){ } // 在这里定义前置切面 @Before...
  • 使用注解来创建切面是 AspectJ 5 所引入的关键特性。我们前一篇已经定义了 Performance 接口,它是切面中切点的目标对象。Q:如何定义切面?A: 给出一个描述:如果一场演出没有观众的话,那就不能称之为演出。对...
  • Springboot Aop 自定义注解切面

    千次阅读 2020-09-02 13:50:25
    Springboot 自定义注解切面 1、创建springboot工程,引入依赖 本次任务实例主要引入以下两个依赖即可。 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> ...
  • 一,了解自定义注解 1.1 自定义注解的定义、描述 注解是一种能被添加到java源代码中的元数据,方法、类、参数和包都可以用注解来修饰。注解可以看作是一种特殊的标记,可以用在方法、类、参数和包上,程序在编译...
  • 解决切面aop中获取不到注解的问题

    千次阅读 2019-09-03 17:11:23
    自己定义了一个注解,然后逻辑代码需要通过获取自定义注解的一个属性来进行权限控制。 下面简单上一下关键代码: 自定义注解: @Documented //有关java doc的注解 @Retention(RetentionPolicy.RUNTIME) //保留...
  • 目标:通过自定义注解 @Ignore 注解,觉得是否读取指定类的属性。 自定义注解:基础详见注解Annotation实现原理与自定义注解例子 运行结果: [main] INFO util.FruitInfoUtil - 水果的名字为:entity.Apple ...
  • java 切面实现记录操作日志
  • 注解就是注解注解,可以在注解接口中使用的注解。 元注解友4个,分别是:@Retention、@Inherited、@Documented、@Target 下面我们一个一个详细了解一下这四个注解都是干什么用的? @Retention(保留):注解...
  • 切面和自定义注解的配合使用

    千次阅读 2016-12-04 00:41:49
    但是切面也有弊端,以笔者的经验看来,使用切面的不方便之处在于切面的精确度问题,我们很难把事务加到大量的指定类的指定方法上,本文就通过Spring AOP和自定义注解的配合使用来解决该问题。 二.Spring AOP切面的...
  • 切面整合自定义注解,对接口请求参数进行校验 jar包依赖 aspectj : "org.aspectj:aspectjweaver:1.9.6", 自定义注解并设置需要校验的字段 @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,144
精华内容 13,257
关键字:

注解切面获取注解属性