上文(设计模式-拦截过滤器模式):https://blog.csdn.net/qq_16498553/article/details/107128062
目录
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
背景
记得刚入行的时候,有一个需求通过用户每次来获取一个固定商品的信息,而我的实现是直接从库中查出再转成对象,然后返回给用户,突然某一天用户量增加了好几百倍,直接把库拉挂了...后面直接用上了缓存,解决了该问题...
服务定位器模式是什么?
服务定位器模式(Service Locator Pattern)用在我们想使用 JNDI 查询定位各种服务的时候。考虑到为某个服务查找 JNDI 的代价很高,服务定位器模式充分利用了缓存技术。在首次请求某个服务时,服务定位器在 JNDI 中查找服务,并缓存该服务对象。当再次请求相同的服务时,服务定位器会在它的缓存中查找,这样可以在很大程度上提高应用程序的性能。
角色:
服务(Service):实际处理请求的服务。对这种服务的引用可以在 JNDI 服务器中查找到。
Context / 初始的 Context :JNDI Context 带有对要查找的服务的引用。
服务定位器(Service Locator): 服务定位器是通过 JNDI 查找和缓存服务来获取服务的单点接触。
缓存(Cache):缓存存储服务的引用,以便复用它们。
客户端(Client):Client 是通过 ServiceLocator 调用服务的对象。
优点:
提升系统性能:由于该模式可以将每次需要返回的固定数据放到缓存中可以减少每次创建对象的开销,很大程度上提升了系统的性能;
缺点:
缓存的实现使系统会比较复杂,如果控制不好会导致内存溢出。
服务定位器模式可以干嘛?
服务定位器模式主要解决一个相同或者公共的数据放到缓存中减少内存开销,并且在一定程序上提升了系统的性能。
个人理解:
比如数据库连接池,不需要每次去连接数据库的时候去创建连接,而是由池去保持一些连接,当需要连接数据库的时候直接获取池中的连接就可以了。
服务定位器模式类图
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
实现代码
/**
* @Auther: csh
* @Date: 2020/7/5 11:44
* @Description:抽象的服务接口
*/
public interface IUserInfo {
public String getName();
public void printUserInfo();
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:45
* @Description:用户信息(Service)
*/
public class User implements IUserInfo {
private String userName;
public void setUserName(String userName) {
this.userName = userName;
}
private User() {
}
public User(String usreName) {
this.userName = usreName;
}
@Override
public String getName() {
return userName;
}
@Override
public void printUserInfo() {
System.out.println("用户信息:"+this.getName());
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
'}';
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:48
* @Description:创建对象(Context )
*/
public class InitialContext {
private static InitialContext initialContext = new InitialContext();
private InitialContext(){
}
public static InitialContext getInstance(){
return initialContext;
}
public Object lookup(String username){
return new User(username);
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 11:51
* @Description:用户缓存
*/
public class UserCache {
private List<IUserInfo> userInfos;
public UserCache() {
userInfos = new ArrayList <IUserInfo>();
}
public IUserInfo getUserInfo(String userName){
for (IUserInfo userInfo : userInfos) {
if(userInfo.getName().equalsIgnoreCase(userName)){
System.out.println("从缓存中获取到用户信息:"+userInfo.toString());
return userInfo;
}
}
return null;
}
public void addUserInfo(IUserInfo userInfo){
boolean exist = false;
for (IUserInfo info : userInfos) {
if(info.getName().equalsIgnoreCase(userInfo.getName())){
exist = true;
}
}
if(!exist){
userInfos.add(userInfo);
}
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 12:06
* @Description:服务定位器(Service Locator)
*/
public class UserInfoLocator {
private static UserCache userCache = new UserCache();
public static IUserInfo getUserInfo(String userName){
IUserInfo userInfo = userCache.getUserInfo(userName);
if(userInfo!=null){
return userInfo;
}
InitialContext instance = InitialContext.getInstance();
IUserInfo user = (IUserInfo)instance.lookup(userName);
userCache.addUserInfo(user);
return user;
}
}
/**
* @Auther: csh
* @Date: 2020/7/5 12:51
* @Description:服务定位器模式
*/
public class Client {
public static void main(String[] args) {
IUserInfo userInfo = UserInfoLocator.getUserInfo("user1");
userInfo.printUserInfo();
userInfo = UserInfoLocator.getUserInfo("user2");
userInfo.printUserInfo();
userInfo = UserInfoLocator.getUserInfo("user1");
userInfo.printUserInfo();
}
}
结果
用户信息:user1
用户信息:user2
从缓存中获取到用户信息:User{userName='user1'}
用户信息:user1
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
最后
服务定位器模式就是将公共或者频繁使用的信息放到缓存中,然后当用户再去获取的时候可以直接从缓存中获取,减少系统开辟内存空间的开销并且可以提升系统性能,大幅度提升资源的利用率。该模式开发中无处不用数据库连接池中的数据库连接、配置信息(账号、密码、连接地址)放到缓存中、spring的一些bean注入等,但是该模式要注意放入缓存中的信息需要添加过期时候,否则可能缓存越堆越大会导致内存溢出问题...
参考文章:
https://www.oracle.com/technetwork/java/servicelocator-137181.html
http://gameprogrammingpatterns.com/service-locator.html