V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
heyjude321
V2EX  ›  Java

请教 Java 类继承问题

  •  
  •   heyjude321 · 2021-11-22 17:00:35 +08:00 · 2554 次点击
    这是一个创建于 1089 天前的主题,其中的信息可能已经有所发展或是发生改变。
    @Service
    public class AuthUserService {
    @Autowired
    private AuthUserDao authUserDao;

    // ----> start
    public static AuthUserService self;

    @Autowired
    public void setService(AuthUserService authUserService) {
    AuthUserService.self = authUserService;
    }
    // ---> end 这部分我想用 BaseService 之类的复用继承
    }

    public interface AuthUserDao extends JpaRepository<AuthUser, Long> {

    }

    我的目的是能通过 AuthUserService .self.functionName() 之类的直接通过类名调用 service 的方法。
    各位 V 友,请教该怎么写 BaseService ,或者有没有更好的方案?
    23 条回复    2021-11-25 10:58:11 +08:00
    chendy
        1
    chendy  
       2021-11-22 17:22:11 +08:00
    目测做不到,因为 static 上下文里没有 this 这个东西,于是除非手动覆盖否则都是走父类的
    如果需求是在静态上下文里取 bean 然后调用方法的话,用 ApplicationContextAware 做一个入口就可以
    chenshun00
        2
    chenshun00  
       2021-11-22 17:40:14 +08:00
    1 、什么需求促使你要这么写?

    2 、如果炫技大可不必,如果不是炫技,可以用下模板模式?
    heyjude321
        3
    heyjude321  
    OP
       2021-11-22 17:52:59 +08:00
    @chenshun00 1.为了让枚举方法里可以使用 service 的方法。2.不是炫技。
    aragakiyuii
        4
    aragakiyuii  
       2021-11-22 19:00:04 +08:00 via iPhone
    如果在启动的时候不使用 AuthUserService ,那可以在枚举里声明 AuthUserService ,然后写个 ApplicationRunner 或者 CommandLineRunner 或者 configuration 手动 set 一下
    ccde8259
        5
    ccde8259  
       2021-11-22 19:05:57 +08:00 via iPhone
    @heyjude321 实现 ApplicationListener<ApplicationStartedEvent>,在 onApplicationEvent(ApplicationStartedEvent)方法里面拿 ApplicationContext 写入 本类的 static 域。开一个 static 方法 T getBean(Class<T>)给枚举类用。
    ccde8259
        6
    ccde8259  
       2021-11-22 19:13:16 +08:00 via iPhone
    不太确定下述写法能否过编译:

    class <T> BaseService<T extends BaseService> {
    protected T self;
    @PostConstruct
    public void injectSelf(T t){
    this.self=t;
    }
    }
    class BaseServiceImpl extends BaseService<BaseServiceImpl> {
    }
    ccde8259
        7
    ccde8259  
       2021-11-22 19:16:47 +08:00 via iPhone
    @ccde8259 应该是自限定类型 也就是 class <T> BaseService<T extends BaseSevice<T>>
    chrisia
        8
    chrisia  
       2021-11-22 20:31:21 +08:00
    applicationContext.getBean
    dranfree
        9
    dranfree  
       2021-11-23 09:46:32 +08:00
    初始化完成之后从 Spring 容器里面取出本类的 bean 然后赋值给静态字段即可,不过一般不这样写,不伦不类的
    wolfie
        10
    wolfie  
       2021-11-23 15:44:17 +08:00
    用 static 不能。
    BaseService 维护一个 map 可以。

    public abstract class BaseService<T extends BaseService<?>> {

    private static final Map<Class<?>, BaseService<?>> map = new ConcurrentHashMap<>();

    public BaseService() {
    map.put(this.getClass(), this);
    }

    T self() {
    return (T) map.get(this.getClass());
    }

    }
    goalidea
        11
    goalidea  
       2021-11-23 16:48:06 +08:00
    如果是枚举里使用 service 简单的方法是 hutool 工具里的 SpringUtil
    heyjude321
        12
    heyjude321  
    OP
       2021-11-24 10:05:38 +08:00
    @ccde8259
    这样不能通过 AuthUserService.self 进行引用,因为 self 不是静态的。
    通过 ApplicationListener 吗?不确定你的方案是什么,但我尝试了本帖其他答主类似的方法,如果父类有 static 方法,则返回值用不了泛型。public static T getSelf() 会报错。
    heyjude321
        13
    heyjude321  
    OP
       2021-11-24 10:16:21 +08:00
    @aragakiyuii 枚举里怎么声明 AuthUserService ?
    EMAIL_PASSWORD("邮箱+密码") {
    @Autowired
    AuthUserService authUserService;

    @Override
    public Result isExist(LoginVO loginVO) {
    return super.isExist(loginVO);
    }

    @Override
    public Result isPassAuth(LoginVO loginVO) {
    return super.isPassAuth(loginVO);
    }

    @Override
    public Result register(LoginVO loginVO) {
    return super.register(loginVO);
    }
    };
    这样不行呐,authUserService 是 null
    heyjude321
        14
    heyjude321  
    OP
       2021-11-24 10:17:23 +08:00
    @wolfie self() 不是 static 的,没办法用过 AuthUserService.self()进行引用。
    heyjude321
        15
    heyjude321  
    OP
       2021-11-24 10:21:09 +08:00
    @dranfree 好像不行。
    父类里写:
    public static T self;
    不能通过编译。
    wolfie
        16
    wolfie  
       2021-11-24 10:30:24 +08:00
    @heyjude321 #14
    static <T> T self(Class<T> clazz) {
    return (T) map.get(clazz);
    }
    dranfree
        17
    dranfree  
       2021-11-24 11:10:26 +08:00
    @heyjude321 啊,你为什么要用泛型,Java 里面静态字段是和对象绑定的
    dranfree
        18
    dranfree  
       2021-11-24 11:15:20 +08:00
    @heyjude321

    ```java
    @Component
    public class DemoServiceImpl implements DemoService, ApplicationContextAware {

    public static DemoService self;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    DemoServiceImpl.self = applicationContext.getBean(DemoService.class);
    }

    @Override
    public String echo(String message) {
    return message;
    }
    }
    ```
    dranfree
        19
    dranfree  
       2021-11-24 11:18:45 +08:00
    @dranfree 至于复用继承,应该是不可行的,因为静态字段和类绑定
    dranfree
        20
    dranfree  
       2021-11-24 11:26:43 +08:00
    @dranfree 这里说错了,应该是字段泛型和对象绑定的
    aragakiyuii
        21
    aragakiyuii  
       2021-11-24 13:09:43 +08:00
    ccde8259
        22
    ccde8259  
       2021-11-24 13:59:18 +08:00 via iPhone
    @heyjude321 ApplicationListener 是用于捕获 ApplicationContext 的。捕获并置入 static 域后才能被 static 的 getBean 方法调用。
    heyjude321
        23
    heyjude321  
    OP
       2021-11-25 10:58:11 +08:00
    @ccde8259
    @aragakiyuii
    @dranfree
    @wolfie
    谢谢各位 V 友的回答,给了我一些启发。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3712 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:21 · PVG 18:21 · LAX 02:21 · JFK 05:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.