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完成生命周期所需内容
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果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 }
以上就是本次注解的项目实践代码分享!菜狗一枚,有更优秀的实现方案欢迎指教!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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代理技术深度解析与实战指南