ServiceLoader使用并结合工厂打造专属多态实例

有几个坑记录下META-INF下services文件夹下文件名要接口全路径名,里面内容是接口实现的全路径名

 

 

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Test3Application {

    public static void main(String[] args) {
        SpringApplication.run(Test3Application.class, args);
    }

}
 

package com.test.bean;

public class Conetxt
{
    private String captchaType;

    public String getCaptchaType()
    {
        return captchaType;
    }

    public void setCaptchaType(String captchaType)
    {
        this.captchaType = captchaType;
    }
    
}
 

 

package com.test.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.test.service.CaptchaService;
import com.test.service.impl.ServiceFactory;


@Configuration
public class ConfigurationSatrt
{
    @Bean
    @ConditionalOnMissingBean
    public CaptchaService captchaService() {
        CaptchaService s = ServiceFactory.getInstance();
        return s;
    }
}
 

package com.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.test.bean.Conetxt;
import com.test.service.CaptchaService;

@Controller
@RequestMapping("test")
public class TestController
{
    @Autowired
    private CaptchaService captchaService;
    
    @RequestMapping("tt")
    public String test()
    {
        Conetxt conetxt = new Conetxt();
        conetxt.setCaptchaType("one");
        return captchaService.get(conetxt);
    }
}
 

 

 

package com.test.service;

import com.test.bean.Conetxt;


public interface CaptchaService
{
    void init();

    String get(Conetxt captchaVO);

    String captchaType();
}
 

 

 

package com.test.service.impl;

import com.test.service.CaptchaService;
import com.test.util.CacheUtil;

public abstract class AbstractService implements CaptchaService
{
    protected static String cacheType = "local";
    
    @Override
    public void init()
    {
        if (cacheType.equals("local")) {
            CacheUtil.init(1000, 180);
        }
    }


}
 

 

package com.test.service.impl;


import org.apache.commons.lang.StringUtils;

import com.google.auto.service.AutoService;
import com.test.bean.Conetxt;
import com.test.service.CaptchaService;

//@AutoService(CaptchaService.class)
public class DefaultServiceImpl extends AbstractService
{

    private CaptchaService getService(String captchaType){
        return ServiceFactory.instances.get(captchaType);
    }

    @Override
    public String get(Conetxt conetxtVO) {
        if (conetxtVO == null) {
            return "对象为空";
        }
        if (StringUtils.isEmpty(conetxtVO.getCaptchaType())) {
            return "类型为空";
        }
        return getService(conetxtVO.getCaptchaType()).get(conetxtVO);
    }
    
    @Override
    public String captchaType()
    {
        return "default";
    }

}
 

 

package com.test.service.impl;

import com.google.auto.service.AutoService;
import com.test.bean.Conetxt;
import com.test.service.CaptchaService;

//@AutoService(CaptchaService.class)
public class OneServiceImpl extends AbstractService
{

    @Override
    public String get(Conetxt captchaVO)
    {
        System.err.println("业务逻辑one");
        return "one";
    }

    @Override
    public String captchaType()
    {
        return "one";
    }

}
 

 

package com.test.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;

import com.test.service.CaptchaService;


public class ServiceFactory
{
    public static CaptchaService getInstance() {
      CaptchaService ret = instances.get("default");
      if (ret == null) {
          throw new RuntimeException();
      }
      ret.init();
      return ret;
  }
    
    public volatile static Map<String, CaptchaService> instances = new HashMap();

    static {
        ServiceLoader<CaptchaService> services = ServiceLoader.load(CaptchaService.class);
        for (CaptchaService item : services) {
            instances.put(item.captchaType(), item);
        }
    }
    
}
 

 

package com.test.service.impl;

import com.google.auto.service.AutoService;
import com.test.bean.Conetxt;
import com.test.service.CaptchaService;

//@AutoService(CaptchaService.class)
public class TwoServiceImpl extends AbstractService
{
    @Override
    public String get(Conetxt captchaVO)
    {
        System.err.println("业务逻辑two");
        return "two";
    }

    @Override
    public String captchaType()
    {
        return "two";
    }

}
 

 

package com.test.util;

import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

public class CacheUtil
{
    private static final Map<String, Object> CACHE_MAP = new ConcurrentHashMap<String, Object>();

    /**
     * 缓存最大个数
     */
    private static Integer CACHE_MAX_NUMBER = 1000;

    /**
     * 初始化
     * @param cacheMaxNumber 缓存最大个数
     * @param second 定时任务 秒执行清除过期缓存
     */
    public static void init(int cacheMaxNumber, long second) {
        CACHE_MAX_NUMBER = cacheMaxNumber;
        if (second > 0L) {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    refresh();
                }
            }, 0, second * 1000);
        }
    }

    /**
     * 缓存刷新,清除过期数据
     */
    public static void refresh(){
        for (String key : CACHE_MAP.keySet()) {
            exists(key);
        }
    }


    public static void set(String key, String value, long expiresInSeconds){
        //设置阈值,达到即clear缓存
        if (CACHE_MAP.size() > CACHE_MAX_NUMBER * 2) {
            clear();
        }
        CACHE_MAP.put(key, value);
        CACHE_MAP.put(key + "_HoldTime", System.currentTimeMillis() + expiresInSeconds*1000);//缓存失效时间
    }

    public static void delete(String key){
        CACHE_MAP.remove(key);
        CACHE_MAP.remove(key + "_HoldTime");
    }

    public static boolean exists(String key){
        Long cacheHoldTime = (Long) CACHE_MAP.get(key + "_HoldTime");
        if (cacheHoldTime == null || cacheHoldTime == 0L) {
            return false;
        }
        if (cacheHoldTime < System.currentTimeMillis()) {
            delete(key);
            return false;
        }
        return true;
    }


    public static String get(String key){
        if (exists(key)) {
            return (String)CACHE_MAP.get(key);
        }
        return null;
    }

    /**
     * 删除所有缓存
     */
    public static void clear() {
        CACHE_MAP.clear();
    }
}
 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.test</groupId>
    <artifactId>test-3</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-3</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <dependency>
            <groupId>com.google.auto.service</groupId>
            <artifactId>auto-service</artifactId>
            <version>1.0-rc7</version>
            <optional>true</optional>
        </dependency>
        
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
 

 

理论上用谷歌com.google.auto.service包添加注解@AutoService也可以自动生成需要配置META-INF下的services文件,但是我使用注解编译后一直没有生成META-INF下的services文件,后续研究下这个注解

 

 

 

稍微修改下的第二个版本,不好地方是初始化失效了,另外不需要配置META-INF下的services文件但是需要在实现类上加上容器注解@Service

package com.test.service.impl;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import com.test.service.CaptchaService;

@Component
public class ServiceFactory implements BeanPostProcessor
{
    public static CaptchaService getInstance() {
      CaptchaService ret = instances.get("default");
      if (ret == null) {
          throw new RuntimeException();
      }

      return ret;
  }
    
    public volatile static Map<String, CaptchaService> instances = new HashMap();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    {
        if (bean instanceof CaptchaService)
        {
            CaptchaService call = (CaptchaService) bean;
            instances.put(call.captchaType(), call);
        }
        
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
    {
        return bean;
    }

}
 

 

 

package com.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.test.bean.Conetxt;
import com.test.service.impl.ServiceFactory;

@Controller
@RequestMapping("test")
public class TestController
{
//    @Autowired
//    private CaptchaService captchaService;
    
    @Autowired
    private ServiceFactory ServiceFactory;
    
    @RequestMapping("tt")
    public String test()
    {
        Conetxt conetxt = new Conetxt();
        conetxt.setCaptchaType("one");
        System.err.println(ServiceFactory.instances.get(conetxt.getCaptchaType()));
//        return captchaService.get(conetxt);
        return null;
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值