• Aop AfterReturning增强方法返回值


    需求:查询订单要返回用户名

      为了解耦,查询订单中不查询用户,使用aop自动注入用户名

        注意:订单列表中的用户缓存到了内存,遍历查询很快,如果直接查数据库,则效率相对低

    思路:对返回值加强(aop对返回值增强,向订单表中注入userName)

      1.注解

    /**
     * 设置属性非空的开关
     * 只有方法上加上此注解,才会对Field上加上 FieldNotNull 的属性赋值
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface SetFieldSwitch {
    }

      

    /**
     * 字段非空注解
     */
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)          //作用在字段上(告诉aop去哪个object调用哪个method,需要传什么param参数,查询的结果需要取哪一个targetField)
    public @interface FieldNotNull {
    
        Class beanClass();  // 需要去哪个class中调用 (userName的属性从)
    
        String method();    // 需要调用class中的哪个方法
    
        String param();     // 调用方法的参数 
    
        String targetField();   //调用方法后需要哪个值(为了set到添加该注解的属性上)
        
    }

      2:订单+用户对象

    @Data
    public class UserOrder /*extends Order*/ {
        private Integer id;
    
        private Integer goodsId;
    
        private Integer userId;
    
        @FieldNotNull(beanClass = UserCache.class, method = "get", param = "userId", targetField = "realName")
        private String userName;    //用户名
    
        private String goodName;    //物品名称
    
        public UserOrder(Integer id, Integer userId, Integer goodId, String userName, String goodName) {
            this.userName = userName;
            this.goodName = goodName;
            this.setId(id);
            this.setUserId(userId);
            this.setGoodsId(goodId);
        }
    
    }

    3:查询订单方法

    @Service
    public class OrderService {
        @Autowired
        private OrderDao orderDao;
    
        @SetFieldSwitch  // 开启aop增强(如果不开启,则FileNotNull注解不会起作用),将控制与实现分开)
    public List<UserOrder> listOrder() {
            return orderDao.listOrder();
        }
    }

    4:查询用户的方法

    /**
     * 模拟用户的缓存
     */
    @Component
    public class UserCache {
        @Autowired
        private UserDao userDao ;
        private static Map<Integer, User> userCache = new HashMap<>();
    
        public void put(Integer userId, User user) {
            userCache.put(userId, user);
        }
    
        public User get(Integer userId) {
            User user = userCache.get(userId);
            if (user == null) {
                user = userDao.getById(userId);
                if (user==null)  return null;
                userCache.put(userId,user);
            }
            return user;
        }
    
        public boolean contain(Integer userId) {
            return userCache.containsKey(userId);
        }
    }

    5:aop切面

        使用AfterReturning

        /**
         *
         * @param point 切点
         * @param obj   返回值
         * @return
         * @throws Throwable
         */
        @AfterReturning(value = "setFieldValuePoint()", returning = "obj")
        public Object setValue(JoinPoint point, Object obj) throws Throwable {
    
            this.setFieldValueForCollection((Collection) obj);
            return obj;
        }

     6:使用反射+注解  赋值

     /**
         * 查询并赋值操作
         *
         * @param collection
         */
        private void setFieldValueForCollection(Collection collection) throws Exception {
            if (collection == null || collection.size() == 0) return;
            Iterator iterator = collection.iterator();
            Object next = iterator.next();
    
            /*collection中userOrder元素对应的class*/
            Class clazz = next.getClass();      // class com.draymond.aop.query.UserOrder
    
            /*获取userOrder中所有的属性*/
            Field[] declaredFields = clazz.getDeclaredFields();
    
            for (Field field : declaredFields) {
                /* ----------- 获取 哪个class 调用哪个 method ,需要什么paras -----------*/
    
                /*获取userOrder属性上的FieldNotNull注解(其他 Field 也可以有其他注解)*/
                FieldNotNull annotation = field.getAnnotation(FieldNotNull.class);
                if (annotation == null) continue;
                field.setAccessible(true);                       // 暴力拆解
                Class beanClass = annotation.beanClass();
                String method = annotation.method();         // get(注解上的值)
                String param = annotation.param();          // userId
                String targetField = annotation.targetField();  // realName
    
                Field paraField = clazz.getDeclaredField(param);    // 获取方法需要的参数值(paraField.get(user)中获取)
                paraField.setAccessible(true);
                Method methodExecute = beanClass.getDeclaredMethod(method, paraField.getType());
    
                /*从spring上下文获取beanClass对应的bean*/
                Object userCache = applicationContext.getBean(beanClass);
    
                // for循环,对list中每个user的带FieldNotNull注解的属性赋值
                for (Object userOrder : collection) {    //list上的每条user对象
    
                    Object user = methodExecute.invoke(userCache, paraField.get(userOrder));   // 执行 UserCache 中的 get 方法,需要的参数值 paraField
                    if (user == null) continue;
                    Field targetFieldValue = user.getClass().getDeclaredField(targetField);    // 获取user对象中的 targetField 的值
                    if (targetFieldValue == null) continue;
                    targetFieldValue.setAccessible(true);
                    field.set(userOrder, targetFieldValue.get(user));                           // 将 user中的targetField(realName) 的值,set到userOrder对象中的 userName
                }
    
            }
    
        }

    其他

    /**
     * 模拟从数据库中查询订单
     */
    @Component
    public class OrderDao {
    
        public List<UserOrder> listOrder() {
    
            UserOrder userOrder1 = new UserOrder(1, 1, 1, "zsc", "电冰箱");
            UserOrder userOrder2 = new UserOrder(2, 1, 2, null, "洗衣机");
            UserOrder userOrder3 = new UserOrder(3, 1, 3, null, "java Thread");
            List list = new ArrayList();
            list.add(userOrder1);
            list.add(userOrder2);
            list.add(userOrder3);
            return list;
        }
    
        public UserOrder getById(Integer id) {
            return listOrder().stream().filter(userOrder -> userOrder.getId() == id).findFirst().orElse(null);
        }
    
    }

    方法上使用注解开启增强

    @Service
    public class OrderService {
        @Autowired
        private OrderDao orderDao;
    
        @SetFieldSwitch
        public List<UserOrder> listOrder() {
            return orderDao.listOrder();
        }
    
        public UserOrder getOrderById(Integer id) {
            return orderDao.getById(id);
        }
    }

    未增强效果

    [{"id":1,"goodsId":1,"userId":1,"userName":"zsc","goodName":"电冰箱"},    // 模拟数据的时候就赋值了
    {"id":2,"goodsId":2,"userId":2,"userName":null,"goodName":"洗衣机"},
    {"id":3,"goodsId":3,"userId":1,"userName":null,"goodName":"java Thread"}]

    增强效果

    [{"id":1,"goodsId":1,"userId":1,"userName":"zsc","goodName":"电冰箱"},
    {"id":2,"goodsId":2,"userId":2,"userName":"draymond","goodName":"洗衣机"},
    {"id":3,"goodsId":3,"userId":1,"userName":"zsc","goodName":"java Thread"}]

     

     

      

  • 相关阅读:
    黑马程序员_超全面的JavaWeb视频教程vedio--.ppt,.pptx,.doc,.txt,.docx列表
    Delphi线程定时器TThreadedTimer及用法--还有TThreadList用法可以locklist
    人人项目renren-securitygit enren-security的目录下的文件列表
    第六天-request response13-request乱码.avi;
    Tip:HttpServletRequest
    第六天-request response4-response实现文件下载.avi--本人测试失败
    response的字节流和字符流输入的区别和问题--02-response的outputStream输出数据的问题.avi
    第六天
    Java-Servlet--《12-WEB应用中的普通Java程序如何读取资源文件.mp4》 有疑问
    Applet、Scriptlet与Servlet
  • 原文地址:https://www.cnblogs.com/draymond/p/12670280.html
Copyright © 2020-2023  润新知