1.错误代码示范
@Component
public class TransferUtilBiz {
/**
* 内部户转账
*/
@Autowired
private InnerAccountTransBiz innerAccountTransBiz;
/**
* 卡转账
*/
@Autowired
private CardTransBiz cardTransBiz;
/**
* 商户转账
*/
@Autowired
private MerchantTransBiz merchantTransBiz;
/**
* 客户转账
*/
@Autowired
private CustomerTransBiz customerTransBiz;
/**
* 转入方
*/
private AbstractCommonTransferBiz transferIn;
/**
* 转出方
*/
private AbstractCommonTransferBiz transferOut;
/**
* 获取转账处理类
* @param entityType 实体类型
* @return 转账处理类
*/
private AbstractCommonTransferBiz getTransfer(String entityType){
switch (EntityTypeEnum.valueOf(entityType)){
case OPERATOR_NO:
return customerTransBiz;
case MERCHANT_NO:
return merchantTransBiz;
case ACCOUNT_NO:
return innerAccountTransBiz;
case CARD_NO:
return cardTransBiz;
default:
return null;
}
}
transferUtilBiz.setTransferOut(EntityTypeEnum.ACCOUNT_NO.getCode());
transferUtilBiz.setTransferIn(createTransOrderBO.getTransInEntityType());
这段代码的逻辑是在转账时根据参数获取对应的转账处理类,比如商户转个人,transferIn就是merchantTransBiz,
transferOut设置customerTransBiz,然后封装各自的参数处理转账。因为spring默认是单例的,所以在多线程的环境下
成员变量transferIn,transferOut可能会被修改,于是造成逻辑上的错误。所以在这个场景下是不应该给TransferUtilBiz 加成员
变量。而是应该直接去取转账的处理类,这样做是正确的。
用一个简单的例子模拟上述场景
public class Singleton {
private static Singleton singleton;
private int count;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(20);
for(int i = 0 ; i < 20 ; i++){
pool.submit(new Add());
}
pool.shutdown();
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public class Add implements Runnable{
@Override
public void run() {
Singleton.getInstance().setCount(Singleton.getInstance().getCount()+1);
System.out.println("当前数字为:"+Singleton.getInstance().getCount());
}
}
上面的Singleton 是单例模式的简单写法(但是这里不能保证绝对是同一个对象),他有一个成员变量count,在线程池中
去累加然后获取值,不能保证数字打印的是一致的,,因为每个线程执行的情况是不一致的。A线程已经取到值17输出,然后代码往下执行一直以它的值为17,但是B线程可能已经将它的值改为19,也就是实际值已经不是预期的了。这就是上面所说的spring是默认单例的,尽量不要使用成员变量。对于上面的情况可以这样解决,下面的方法就是有序的了。最后说一下spring容器
在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例)
singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。
使用注解可以这么设置:
public class Singleton {
private static Singleton singleton;
private int count;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(20);
for(int i = 0 ; i < 100 ; i++){
pool.submit(new Add());
}
pool.shutdown();
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public static synchronized void add(){
Singleton s = Singleton.getInstance();
s.setCount(s.getCount()+1);
System.out.println("当前数字为:"+s.getCount());
}
}
public class Add implements Runnable{
@Override
public void run() {
Singleton.add();
}
}
2.正确代码示范
@Component
public class TransferUtilBiz {
/**
* 内部户转账
*/
@Autowired
private InnerAccountTransBiz innerAccountTransBiz;
/**
* 卡转账
*/
@Autowired
private CardTransBiz cardTransBiz;
/**
* 商户转账
*/
@Autowired
private MerchantTransBiz merchantTransBiz;
/**
* 客户转账
*/
@Autowired
private CustomerTransBiz customerTransBiz;
/**
* 获取转账处理类
* @param entityType 实体类型
* @return 转账处理类
*/
public AbstractCommonTransferBiz getTransfer(String entityType){
switch (EntityTypeEnum.valueOf(entityType)){
case OPERATOR_NO:
return customerTransBiz;
case MERCHANT_NO:
return merchantTransBiz;
case ACCOUNT_NO:
return innerAccountTransBiz;
case CARD_NO:
return cardTransBiz;
default:
throw new TradeProductException(BizErrorCode.ENTITY_TYPE_IS_ILLEGAL.getCode(),
BizErrorCode.ENTITY_TYPE_IS_ILLEGAL.getDesc());
}
}
//卡作为出账方支付工具
transferUtilBiz.getTransfer(createTransOrderBO.getTransOutEntityType()).setFundOutPayTool(createTransOrderBO);
//卡通用转账入帐方支付工具
transferUtilBiz.getTransfer(createTransOrderBO.getTransInEntityType()).setFundInPayTool(createTransOrderBO);
3.如何在测试时复现这种问题。
一般在测试环境是单线程环境,因此会忽略多线程的情况。现在有一些并发测试工具,可以模拟多线程环境。
如https://download.csdn.net/download/u013822349/10265013
4.如何以多态处理复杂条件表达式
这块代码原逻辑看起来比较复杂
可以按照类似下面的方式将条件表达式分解
public abstract class Employee {
private int _type;
static final int ENGINEER = 0;
static final int SALESMEN = 1;
static final int MANAGER = 2;
public abstract int getType();
static Employee create(int type){
switch (type){
case ENGINEER:
return new Engineer();
case SALESMEN:
return new Salesmen();
case MANAGER:
return new Manager();
default:
throw new IllegalArgumentException("Incorrect type code default");
}
}
abstract void excute();
}
public class Engineer extends Employee{
@Override
public int getType(){
return Employee.ENGINEER;
}
@Override
void excute() {
System.out.println("ENGINEER");
}
}
public class Manager extends Employee{
@Override
public int getType(){
return Employee.MANAGER;
}
@Override
void excute() {
System.out.println("MANAGER");
}
}
public class Salesmen extends Employee{
@Override
public int getType(){
return Employee.SALESMEN;
}
@Override
void excute() {
System.out.println("SALESMEN");
}
}
public class Main {
public static void main(String[] args) {
Employee.create(Employee.SALESMEN).excute();
}
}