项目中缓存服务CacheService继承的BaseService抽象类源码学习,其他服务层实现类在同包名下也有在使用(CacheService继承BaseService,其他不同模块相同包名的,继承CacheService)。
Golang、前端所没有的 …(回顾面向对象)
Java 抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
BaseService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import com.xxx.appserver.commons.support.JsonUtility; import com.xxx.appserver.commons.support.SpringContextUtility; import com.fasterxml.jackson.databind.JsonNode; import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
public abstract class BaseService<S> {
protected S proxy; @Autowired protected SpringContextUtility springContextUtility;
@PostConstruct protected void post() {
Class<?>[] interfaces = this.getClass().getInterfaces(); if(null == interfaces || interfaces.length == 0) return; proxy = (S) springContextUtility.getBean(interfaces[0]); }
protected JsonNode getNodeList(String json) throws Exception { JsonNode node = JsonUtility.readTree(json); return node.get("list"); } }
|
泛型类:在编译器,是无法知道S具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。(项目中一般传的是服务接口)
声明泛型proxy,通过post方法从Bean中获取到对应接口信息的接口实现,即在继承使用的类中可以通过proxy调用其他服务的方法,就是使用到SpringContextUtility,下面分析。
SpringContextUtility
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
@Component public class SpringContextUtility implements ApplicationContextAware {
@Getter private static ApplicationContext applicationContext;
@Override public void setApplicationContext(ApplicationContext application) throws BeansException { applicationContext = application; }
public static Object getBean(String name) throws BeansException { return applicationContext.getBean(name); }
public static <T> T getBean(Class<T> clazz) { return applicationContext.getBean(clazz); } }
|
创建个类实现ApplicationContextAware工具类,可以通过其它类引用它以操作spring容器及其中的Bean实例。
Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给该类对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。
使用
还是登陆方法吧
UserServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Slf4j @Service @CacheConfigList({ @CacheConfiguration(nameSpace = CacheKey.GAME_CATCH_USER, expTime = 172800) }) public class UserServiceImpl extends CacheService<IUserService> implements IUserService {
@Override public UserDto login(String code, String encryptedData, String iv) throws Exception {
...
UserDto user = proxy.queryUserByUid(wxUser.getOpenId());
...
proxy.saveUserByUid(user); log.info("用户登录:" + user); return user; } }
|
可以看到这个实现类继承了CacheService,泛型传的是IUserService接口,通过proxy我们就可以调到接口实现的方法了,下面是IUserService接口
IUserService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public interface IUserService {
UserDto login(String code, String encryptedData, String iv) throws Exception;
UserDto saveUserByUid(UserDto userDto);
UserDto queryUserByUid(String uid); }
|