我有一个带有ThreadLocal变量的上下文类,我想用它来存储数据。
LDAPAttributesContextHolder
public class LDAPAttributesContextHolder {
private static final ThreadLocal<List<Attributes>> threadLocalScope = new ThreadLocal<>();
private LDAPAttributesContextHolder() {
throw new IllegalStateException("ThreadLocal context class");
}
public static final List<Attributes> getAttributes() {
return threadLocalScope.get();
}
public static final void setAttributes(List<Attributes> attributes) {
threadLocalScope.set(attributes);
}
public static final void destroy() {
threadLocalScope.remove();
}
}
我使用此类存储用户属性,并将其用于其他服务。
服务1
@Override
public boolean searchInLDAP(String userName, String email) {
LOG.debug("Current thread is {}", Thread.currentThread().getName());
LOG.debug("Start search user with login {} and email {} in LDAP directory", userName, email);
List<Attributes> attributeList = new ArrayList<>();
if(isEmpty(LDAPAttributesContextHolder.getAttributes())) {
attributeList = ldapTemplate.search(query().base("ou=people").where("uid").is(userName).and("mail").is(email),
(AttributesMapper<Attributes>) attributes -> {
if(attributes == null) {
return null;
}
return attributes;
});
LDAPAttributesContextHolder.setAttributes(attributeList);
}
LOG.debug("Status of searching user with login {} and email {} in LDAP is {}", userName, email, (!isEmpty(attributeList)) ? "success" : "failed");
if(nonNull(attributeList) && !isEmpty(attributeList)) {
logAttributes(userName);
}
return nonNull(attributeList) && !isEmpty(attributeList);
}
服务2
public List<String> getAllFacultyGroupNamesByFacultyName() {
String studentFacultyName = "";
LOG.debug("Current thread is {}", Thread.currentThread().getName());
LOG.debug("LDAPContextHolder size {}", LDAPAttributesContextHolder.getAttributes().size());
List<Attributes> attributeList = LDAPAttributesContextHolder.getAttributes();
LOG.debug("In method {} ,Size of attributes is {}", Thread.currentThread().getStackTrace()[0].getMethodName(), attributeList.size());
for(Attributes attributes : attributeList) {
try {
if(attributes.get(FACULTY_ATTRIBUTE) != null &&
attributes.get(ROLE_ATTRIBUTE) != null &&
!attributes.get(ROLE_ATTRIBUTE).get().toString().equals(ORGANIZATIONAL_PERSON)
) {
studentFacultyName = attributes.get(FACULTY_ATTRIBUTE).get().toString();
studentFacultyName = studentFacultyName.contains(IT_FACULTY.toLowerCase()) ? IT_FACULTY : studentFacultyName;
LOG.debug("Student faculty is {}", studentFacultyName);
}
} catch(NamingException e) {
LOG.error("Error while parsing LDAP attributes. {}", e);
}
}
return ...;
}
问题在于,在第一个方法线程中为120,但在第二个线程中由于某种原因,线程为115,当我尝试获取上下文时,它抛出NullPointer。
我错过了什么?
最佳答案
ThreadLocal
保存一个引用per thread。因此,除非每个线程对其进行初始化,否则您将获得空指针异常。从Javadoc:
这些变量与普通变量不同,因为每个访问一个线程(通过其get
或set
方法)的线程都有其自己的,独立初始化的变量副本。
听起来像您想要单例模式。由于您使用的是Spring Boot,因此可以创建类型为LDAPAttributesContextHolder
的bean,并将其自动连接到我们使用过的组件/服务中。
关于java - Tomcat的ThreadLocal,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55401895/