项目自学记录5


项目自学目录5

Resource 和 Autowire

@Autowired

  • 类型注入

@Resource

  • 名字注入优先,找不到名字找类型

Resource直接注入失败,要调get方法的问题

在conf里

    /**
     * 税控发票库存同步任务
     */
    @Bean({"invStocSyncJobService"})
    @ConditionalOnMissingBean(name = {"invStocSyncJobService"})
    public InvStocSyncJobService invStocSyncJobService(){
        //注意这里要对应好
        if(PROVIDER_HLZS.equalsIgnoreCase(provider)){
            return new InvStocSync4HLJobServiceImpl();
        }
        return null;
    }

最终会导致InvStocSyncJobService 的返回值为Null。

所以对于下面的handler类来说

public class InvStocSyncJobHandler {

    private InvStocSyncJobService getInvStocSyncJobService() {
        return SpringUtils.getBean("invStocSyncJobService");
    }
}

这个get方法代替的是

@Resource
InvStocSyncJobService invStocSyncJobService

下面所有的invStocSyncJobService.函数,也变为getInvStocSyncJobService().函数

应该是一个注入时间的问题

如果你要在实例化一个类的时候把另一个类以属性的方式注入那你就用@Resource好了,
但是不想那么早注入,只在某个方法被调用时采取获取那个对象那就用context.getBean()呗。

如果实例化类的时候(很早)就注入,会导致程序无法启动成功。用下面这种方式程序可以启动也可以跑通。

其中的SpringUtils是自己写的工具类

@Component
public final class SpringUtils implements BeanFactoryPostProcessor {
    private static ConfigurableListableBeanFactory beanFactory;

    public SpringUtils() {
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    public static <T> T getBean(String name) throws BeansException {
        return beanFactory.getBean(name);
    }

    public static <T> T getBean(Class<T> clz) throws BeansException {
        T result = beanFactory.getBean(clz);
        return result;
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> clz) throws BeansException {
        return beanFactory.getBeansOfType(clz);
    }

    public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException {
        return beanFactory.getBeansWithAnnotation(annotationType);
    }

    public static boolean containsBean(String name) {
        return beanFactory.containsBean(name);
    }

    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.isSingleton(name);
    }

    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getType(name);
    }

    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getAliases(name);
    }

    public static <T> T getAopProxy(T invoker) {
        return AopContext.currentProxy();
    }
}

Future的get()方法

JDK里的Future

比如启动一个main方法,main中又包含了若干个其它任务,在不使用Java Future的情况下,main方法中的任务会同步阻塞执行,一个执行完成后,才能去执行另一个;如果使用java Future,则main方法中的任务会异步执行,main方法不用等待一个任务的执行完成,只需往下执行就行。一个任务的执行结果又该怎么获取呢?这里就需要用到Future接口中的isDone()方法来判断任务是否执行完,如果执行完成则可获取结果,如果没有完成则需要等待。 可见虽然主线程中的多个任务是异步执行,但是无法确定任务什么时候执行完成,只能通过不断去监听以获取结果,所以这里是阻塞的。这样,可能某一个任务执行时间很长会拖累整个主任务的执行。

如果用java.util.concurrent.Future这种原生的,要使用while循环不停的监听。而且结果是先输出第一行,然后光速输出第二第三行。

Thread1 ——> Task1 10s
Thread2 ——> Task2 2s
Thread3 ——> Task3 3s

package com.aplus.controller;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
 
/**
 * @author whb
 */
@Slf4j
@RestController
@RequestMapping(value = "/api/guava")
public class GuavaController {
 
    public static final ExecutorService service = Executors.newCachedThreadPool();
 
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
 
        // 任务1
        Future<Boolean> booleanTask = service.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                return true;
            }
        });
 
        // 任务2
        Future<String> stringTask = service.submit(new Callable<String>() {
 
            @Override
            public String call() throws Exception {
                Thread.sleep(3000);
                return "Hello World";
            }
        });
 
        // 任务3
        Future<Integer> integerTask = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(2000);
                return new Random().nextInt(100);
            }
        });
 
        while (true) {
            if (booleanTask.isDone() && !booleanTask.isCancelled()) {
                Boolean result = booleanTask.get();
                System.err.println("任务1-10s: " + result);
                break;
            }
        }
 
        while (true) {
            if (stringTask.isDone() && !stringTask.isCancelled()) {
                String result = stringTask.get();
                System.err.println("任务2-3s: " + result);
                break;
            }
        }
 
        while (true) {
            if (integerTask.isDone() && !integerTask.isCancelled()) {
                Integer result = integerTask.get();
                System.err.println("任务3-2s:" + result);
                break;
            }
        }
 
        // 执行时间
        System.err.println("time: " + (System.currentTimeMillis() - start));
 
    }
 
}

Guava里的Future

Guava Future 能够 减少主函数的等待时间,使得多任务能够异步非阻塞执行

ListenableFuture是可以监听的Future,它是对java原生Future的扩展增强。Future表示一个异步计算任务,当任务完成时可以得到计算结果。如果希望计算完成时马上就拿到结果展示给用户或者做另外的计算,就必须使用另一个线程不断的查询计算状态。这样做会使得代码复杂,且效率低下。如果使用ListenableFuture,Guava会帮助检测Future是否完成了,如果完成就自动调用回调函数,这样可以减少并发程序的复杂度。

package com.aplus.controller;
 
import com.google.common.util.concurrent.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
 
/**
 * @author whb
 */
@Slf4j
@RestController
@RequestMapping(value = "/api/guava")
public class GuavaController {
    
    public static final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
 
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
 
        // 任务1
        ListenableFuture<Boolean> booleanTask = service.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Thread.sleep(10000);
                return true;
            }
        });
 
        Futures.addCallback(booleanTask, new FutureCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean result) {
                System.out.println("BooleanTask.任务1-10s: " + result);
            }
 
            @Override
            public void onFailure(Throwable throwable) {
                System.out.println("BooleanTask.throwable: " + throwable);
            }
        });
 
        // 任务2
        ListenableFuture<String> stringTask = service.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(3000);
                return "Hello World";
            }
        });
 
        Futures.addCallback(stringTask, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                System.out.println("StringTask.任务2-3s: " + result);
            }
 
            @Override
            public void onFailure(Throwable t) {
            }
        });
 
        // 任务3
        ListenableFuture<Integer> integerTask = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(2000);
                return new Random().nextInt(100);
            }
        });
 
        Futures.addCallback(integerTask, new FutureCallback<Integer>() {
            @Override
            public void onSuccess(Integer result) {
                System.err.println("IntegerTask.任务3-2s:: " + result);
            }
 
            @Override
            public void onFailure(Throwable t) {
            }
        });
 
        // 执行时间
        System.err.println("time: " + (System.currentTimeMillis() - start));
    }
 
}

Thread1 ——> Task1 10s
Thread2 ——> Task2 2s
Thread3 ——> Task3 3s

执行结果是可以先输出Task2和Task3

说明它获取结果时,只要结果有反馈,就能获取到,因为它是非阻塞的。

threadPool的shutdown方法

将线程池状态置为SHUTDOWN,并不会立即停止:

  • 停止接收外部submit的任务
  • 内部正在跑的任务和队列里等待的任务,会执行完
  • 等到第二步完成后,才真正停止
singleThreadPool.execute(() -> {
    ...
});
singleThreadPool.shutdown();

PostConstruct注解

该注解的方法在整个Bean初始化中的执行顺序:

Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的初始化方法)

该注解的功能:当依赖注入完成后用于执行初始化的方法,并且只会被执行一次

import javax.annotation.PostConstruct;
 
@Component
public class Utils {
 
    @Autowired
    private UserService userService;
 
    @PostConstruct
    void init() {
        userService.doSomething();  //userService注入后执行一些初始化操作
    }
 
}

前端刷新按钮的书写

首先找到应该在前端哪个页面,哪个位置写。

因为是发送post请求,所以简单的导入一个post

import { post } from '@/utils/ajax'

然后就是写@click对应的函数

    updateTest(){
      post("http://127.0.0.1:9998/handlers",null);

    },

IDEA在打断点期间。Ctrl+u进入Evaluate Expression界面

可以输入一些代码,进行调试。得到粒度更细的结果。

一个Service如何搞多个ServiceImpl

以前的普通实现类,都是类似这种,一个service绑定一个ServiceImpl

@Service
public class TaxPeriodAndStatStateSync4LqJobServiceImpl implements TaxPeriodAndStatStateSyncJobService

如果要搞多个,就要自己配置. 搞个配置类


/**
 * 任务实现配置器
 */
@Configuration
public class InputinvJobConfiguration {

    /**
     * 合力中税
     */
    private static final String PROVIDER_HLZS = "hlzs";

    /**
     * 乐企
     */
    private static final String PROVIDER_LQ = "lq";

    /**
     * lq, hlzs
     */
    @Value("${zbiti.config.vat.job.inputinv.service}")
    private String provider;
    
     /**
     * 税款所属期及属期统计状态同步任务
     * @return
     */
    @Bean({"taxPeriodAndStatStateSyncJobService"})
    @ConditionalOnMissingBean(name = {"taxPeriodAndStatStateSyncJobService"})
    public TaxPeriodAndStatStateSyncJobService taxPeriodAndStatStateSyncJobService() {
        if (PROVIDER_LQ.equalsIgnoreCase(provider)) {
            return new TaxPeriodAndStatStateSync4LqJobServiceImpl();
        } else if(PROVIDER_HLZS.equals(provider)){
            return new TaxPeriodAndStatStateSync4HLJobServiceImpl();
        }
        return null;
    }

是合力的就走合力的实现类Impl,是乐企的就走乐企的。

两个注解的意思是,如果没有在Spring容器里找到这个,就在这进行初始化为Bean

@XxlJob(value = “TaxpayerInfoJobHandler”, label = “纳税人基础信息同步任务”, params = {})

其实这个注解没有很理解,因为暂时还没碰到xxlJob。

这个的结果是

String.format可以实现一定的正则效果

String title = "税控发票库存同步任务 ";
String tmpMsg = String.format(">>>>>%s开始", title);

https://blog.csdn.net/lonely_fireworks/article/details/7962171

StringUtil.isEmpty和StringUtil.isBlank

直接看源码

public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
}
public static boolean isBlank(String str) {
    int strLen;
    if (str != null && (strLen = str.length()) != 0) {
        for(int i = 0; i < strLen; ++i) {// 判断字符是否为空格、制表符、tab
            if (!Character.isWhitespace(str.charAt(i))) {
                return false;
            }
        }
        return true;
    } else {
        return true;
    }
}

isEmpty只支持两种情况,isBlank还多支持多个空格的字符串情况

finally的注意事项-不要写return

public static int test(){
try{
    return 10;}
 finally{
    return20;}
}

这样,无论最后有没有异常,都是return 20

而且如果finally里有return的话,会吞掉异常!!

try-with-resources

try(InputStreamis=newFileInputStream("d:\\1.txt")){
System.out.println(is);}
catch(IOExceptione){
e.printStackTrace();}

可以把实现了资源接口的放到try的括号里。编译器会自动在finally里关闭资源。(重写代码)

他会写两个try,非常严谨。

对金额的处理 joda-money

存储金额的数据类型Decmial。

在Java中,可以使用java.math.BigDecimal类来表示Decimal类型的数据。BigDecimal对象可以存储任意精度的小数,具有高度的可靠性和精度。使用BigDecimal来存储金额等金融数据时,需要注意设置其精度和舍入模式,以确保数据的准确性。

除了BigDecimal之外,还有一些其他的数据类型可以用来存储金额等金融数据。例如,可以使用long类型来存储以分为单位的金额,这样可以避免使用浮点数产生的精度问题。在需要进行计算时,可以将long类型的金额转换为BigDecimal类型进行运算。

另外,还可以使用一些开源的库,如joda-moneymoney-api等,它们提供了更加方便和可读的API来处理货币和金额等金融数据。这些库可以自动处理金额的舍入、转换和格式化等问题,方便程序员进行开发和维护。

import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
Coffee latte = new Coffee()
                .withName("latte")
                .withPrice(Money.of(CurrencyUnit.of("CNY"), 30.0));

当然对应的还有很多要配置的,money和long之间的转换,在Mybatis中也要配置。

Nosql的了解

一般分为四大类:

  1. k-v类型的 ,比如redis
  2. 文档类型的,比如mongoDB
  3. 列存储的,HBase
  4. 图数据库,比如Ne04j

文章作者: 爱敲代码の鱼儿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 爱敲代码の鱼儿 !
  目录