spring注解项目实践

 
基础知识准备
一、注解基础知识
1、 public @interface实现一个注解类
2、@target 该注解的用于什么地方 
  ●ElementType.CONSTRUCTOR: 用于描述构造器
  ● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
  ● ElementType.LOCAL_VARIABLE: 用于描述局部变量
  ● ElementType.METHOD: 用于描述方法
  ● ElementType.PACKAGE: 用于描述包
  ● ElementType.PARAMETER: 用于描述参数
  ● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明
3 、@Retention:该注解什么时候使用
●   RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们 不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  ●   RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
  ●   RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
4、Inherited 是否允许子类实现
二、spring bean完成生命周期所需内容
   
  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中
  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
业务实践:
1、业务场景:
有退费、升班、转班、转校四种售后,四种售后都有保存、提交、审核通过、提交后处理等共同的业务流程,单每种售后都有自己独特的业务逻辑和共同逻辑,为了代码简洁雅观以及扩展性,所以这里考虑使用策略模式来实现这种业务场景,而要实现策略模式这里工厂模式的作用就自然而然的出来了。
2、代码实现:
注解类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AfterSale {
AfterSaleTypeEum value() ;
}

售后枚举

复制代码
 1 package com.hq.schoolcj.util.enums;
 2 
 3 
 4 import cn.hutool.core.util.ObjectUtil;
 5 import com.hq.schoolcj.common.annotation.exception.CustomException;
 6 
 7 public enum AfterSaleTypeEum {
 8     REFUND(0, "退费"),
 9     UP_CLASS(1, "升班"),
10     TURN_CLASS(2, "转班"),
11     TURN_SCHOOL(3, "转校");
12 
13     private int number;
14 
15     private String afterSaleType;
16 
17     AfterSaleTypeEum(int number, String afterSaleType) {
18         this.number = number;
19         this.afterSaleType = afterSaleType;
20     }
21 
22     public int getNumber() {
23         return number;
24     }
25 
26     public String getAfterSaleType() {
27         return afterSaleType;
28     }
29 
30     public Integer getValue() {
31         return number;
32     }
33 
34     public static AfterSaleTypeEum getById(Integer number) {
35         if(ObjectUtil.isEmpty(number)){
36             throw new CustomException("参数错误:请传入售后类型!",EnumCode.NOT_EXIST.getCode());
37         }
38         for (AfterSaleTypeEum afterSaleType : values()) {
39             if (afterSaleType.getNumber() == number) {
40                 //获取指定的枚举
41                 return afterSaleType;
42             }
43         }
44         return null;
45     }
46 }
复制代码

 

售后流程接口

复制代码
package com.hq.schoolcj.aftersale.service;

import com.hq.schoolcj.aftersale.domain.vo.AftersaleVo;
import com.hq.schoolcj.util.enums.AfterSaleTypeEum;

public interface AfterSaleManageService {

/**
* 提交
*
* @param aftersaleVo
*/
void submit(AftersaleVo aftersaleVo);

/**
* 提交后处理
*
* @param aftersaleVo
*/
void afterSubmitHandle(AftersaleVo aftersaleVo);

/**
* 审核通过
*
* @param aftersale 售后单对象
*/
void checkAccess(AftersaleVo aftersale);

/**
*
* 推送nc消息
* @param aftersaleVo
*/
void sendNcMessage(AftersaleVo aftersaleVo);


}
复制代码

售后流程退费实现类

复制代码
 1 package com.hq.schoolcj.aftersale.service.impl;
 2 
 3 import cn.hutool.core.thread.ThreadUtil;
 4 import cn.hutool.core.util.ObjectUtil;
 5 import com.hq.schoolcj.aftersale.domain.vo.AftersaleVo;
 6 import com.hq.schoolcj.aftersale.mapper.AftersaleDao;
 7 import com.hq.schoolcj.aftersale.service.AfterSaleExpand;
 8 import com.hq.schoolcj.aftersale.service.RefundService;
 9 import com.hq.schoolcj.aftersale.util.AfterSale;
10 import com.hq.schoolcj.common.annotation.exception.CustomException;
11 import com.hq.schoolcj.dingTalkProcess.service.DingTalkProcessService;
12 import com.hq.schoolcj.presale.service.NcMessageService;
13 import com.hq.schoolcj.util.enums.AfterSaleTypeEum;
14 import com.hq.schoolcj.util.enums.EnumCode;
15 import lombok.extern.slf4j.Slf4j;
16 import org.springframework.beans.factory.annotation.Autowired;
17 import org.springframework.stereotype.Service;
18 
19 @AfterSale(AfterSaleTypeEum.REFUND)
20 @Service
21 @Slf4j
22 public class RefundServiceImpl implements RefundService {
23 32 
33     @Override
34     public void submit(AftersaleVo aftersaleVo) {
35 //1、业务逻辑 36 41 } 42 43 @Override 44 public void afterSubmitHandle(AftersaleVo aftersaleVo) { 45 //业务逻辑47 } 48 49 @Override 50 public void checkAccess(AftersaleVo aftersale) { 51 52 //业务逻辑57 } 58 59 @Override 60 public void sendNcMessage(AftersaleVo aftersaleVo) { 61 //业务逻辑 62 } 63 }
复制代码

售后流程升班实现类

复制代码
package com.hq.schoolcj.aftersale.service.impl;

import com.hq.domain.Enums.BUSINESS;
import com.hq.domain.entity.order.WxTradeOrderRegistrationInformationTempEntity;
import com.hq.schoolcj.aftersale.domain.AftersaleDetail;
import com.hq.schoolcj.aftersale.domain.AftersaleOrder;
import com.hq.schoolcj.aftersale.domain.WxTradeOrderExtraTemp;
import com.hq.schoolcj.aftersale.domain.WxTradeOrderTemp;
import com.hq.schoolcj.aftersale.domain.vo.AftersaleOrderVo;
import com.hq.schoolcj.aftersale.domain.vo.AftersaleVo;
import com.hq.schoolcj.aftersale.mapper.AftersaleDao;
import com.hq.schoolcj.aftersale.service.AfterSaleExpand;
import com.hq.schoolcj.aftersale.service.AftersaleService;
import com.hq.schoolcj.aftersale.service.UpClassService;
import com.hq.schoolcj.aftersale.util.AfterSale;
import com.hq.schoolcj.common.annotation.exception.CustomException;
import com.hq.schoolcj.presale.domain.WxTradeOrderExtraEntity;
import com.hq.schoolcj.presale.domain.WxTradeOrderRegistrationInformationEntity;
import com.hq.schoolcj.presale.domain.pojo.CreateOrderVO;
import com.hq.schoolcj.presale.service.NcMessageService;
import com.hq.schoolcj.presale.service.WxTradeOrderService;
import com.hq.schoolcj.util.ObjectUtils;
import com.hq.schoolcj.util.enums.AfterSaleStatusEnumCode;
import com.hq.schoolcj.util.enums.AfterSaleTypeEum;
import com.hq.schoolcj.util.enums.EnumCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@AfterSale(AfterSaleTypeEum.UP_CLASS)
@Service
@Slf4j
public class UpClassServiceImpl implements UpClassService {

    @Override
    public void submit(AftersaleVo aftersaleVo) {

       //业务逻辑

    }

    @Override
    public void afterSubmitHandle(AftersaleVo aftersaleVo) {
         //业务逻辑
    }

    @Override
    public void checkAccess(AftersaleVo aftersale) {
        //业务逻辑
    }
   @Override
   public void sendNcMessage(AftersaleVo aftersaleVo) {
        //业务逻辑
   }
}
复制代码

工厂模式实现,在spring bean初始化是将对应的实例化对象放入map容器中,以便使用时获取。这里 是在springBean生命周期第五步的时候去做此操作。

复制代码
 1 package com.hq.schoolcj.aftersale.util;
 2 
 3 import com.hq.schoolcj.aftersale.service.AfterSaleManageService;
 4 import com.hq.schoolcj.util.enums.AfterSaleTypeEum;
 5 import org.springframework.beans.BeansException;
 6 import org.springframework.beans.factory.InitializingBean;
 7 import org.springframework.context.ApplicationContext;
 8 import org.springframework.context.ApplicationContextAware;
 9 import org.springframework.stereotype.Component;
10 
11 import java.util.Map;
12 
13 @Component
14 public class HandlerWarehouseProcessor implements ApplicationContextAware  {
15 
16 
17     @Override
18     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
19         // 获取自定义注解的类
20         Map<String, Object> mapClass=applicationContext.getBeansWithAnnotation(AfterSale.class);
21         //根据key(注解的值) value(增加注解的类既实现类) 存储到map中
22         mapClass.forEach((k,v)->{
23             Class<AfterSaleManageService> warehouseStrategyClass =(Class<AfterSaleManageService>)v.getClass();
24 
25             AfterSaleTypeEum afterSaleType =warehouseStrategyClass.getAnnotation(AfterSale.class).value();
26 
27             HandlerWarehouseContext.wareHouseStrategyBeanMap.put(afterSaleType,warehouseStrategyClass);
28         });
29     }
30 }
复制代码

接下来提供工厂类以及对应实现类的获取方法

复制代码
 1 package com.hq.schoolcj.aftersale.util;
 2 
 3 import com.hq.schoolcj.aftersale.service.AfterSaleManageService;
 4 import com.hq.schoolcj.util.enums.AfterSaleTypeEum;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.context.ApplicationContext;
 7 import org.springframework.stereotype.Component;
 8 
 9 import java.util.HashMap;
10 import java.util.Map;
11 
12 
13 /**
14  *
15  * @author lishilei
16  * @since 2021-03-20 14:12:19
17  */
18 @Component
19 public class HandlerWarehouseContext {
20 
21     @Autowired
22     private ApplicationContext applicationContext;
23     /**
24      * 存放所有策略类Bean的map
25      */
26     public static Map<AfterSaleTypeEum, Class<AfterSaleManageService>> wareHouseStrategyBeanMap=new HashMap<>();
27 
28     public AfterSaleManageService getAfterSaleService(AfterSaleTypeEum afterSaleType){
29         Class<AfterSaleManageService> strategyClass = wareHouseStrategyBeanMap.get(afterSaleType);
30         if(strategyClass==null){
31             throw new IllegalArgumentException("未找到对应"+ afterSaleType.getAfterSaleType()+"服务: " );
32         }
33         // 从容器中获取对应的策略Bean
34         return applicationContext.getBean(strategyClass);
35     }
36 
37 }
复制代码

接下来就是具体的使用了

复制代码
 1 public void checkAccess(Long id) {
 2         //业务逻辑
 3         //1、获取售后类型
 4         AfterSaleTypeEum afterSaleTypeEum = AfterSaleTypeEum.getById(aftersale.getAftersaleType());
 5         //2、根据售后类型获取对应服务
 6         AfterSaleManageService afterSaleService = handlerWarehouseContext.getAfterSaleService(afterSaleTypeEum);
 7        //方法调用
 8         afterSaleService.checkAccess(aftersale);
 9        
10     }    
复制代码

 以上就是本次注解的项目实践代码分享!菜狗一枚,有更优秀的实现方案欢迎指教!

 

posted @   lsl547445  阅读(93)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示