Yan Hong 박사의 저서 "JAVA and Patterns"는 책임 사슬 모델에 대한 설명으로 시작됩니다.
책임 사슬 패턴은 객체 행동 패턴입니다. 책임 사슬 패턴에서는 많은 객체가 연결되어 각 객체의 자손에 대한 참조를 통해 체인을 형성합니다. 요청은 체인의 개체가 요청을 처리하기로 결정할 때까지 체인 위로 전달됩니다. 요청을 하는 클라이언트는 체인의 어떤 개체가 최종적으로 요청을 처리하는지 알지 못하므로 시스템은 클라이언트에 영향을 주지 않고 동적으로 재구성하고 책임을 할당할 수 있습니다.
북을 치고 꽃을 피우는 것부터 시작해
북을 치며 꽃을 넘기는 것은 활기차고 긴장감 넘치는 음주 게임입니다. 연회에서는 손님들이 순서대로 앉고, 한 사람이 북을 치며, 북을 치는 곳과 꽃을 전달하는 곳을 분리하여 공정함을 표현한다. 북소리가 시작되면 꽃다발이 전달되기 시작하고, 북이 떨어지자마자 꽃다발이 누군가의 손에 있으면 그 사람은 술을 마셔야 한다.
예를 들어 Jia Mu, Jia She, Jia Zheng, Jia Baoyu 및 Jia Huan은 북 연주 및 꽃 전달 게임에 참여하는 5명의 꽃 전달자입니다. 드러머는 자무에게 꽃을 전달하고 꽃 전달 게임을 시작했습니다. 꽃은 아래 그림과 같이 Jia Mu에서 Jia She로, Jia She에서 Jia Zheng으로, Jia Zheng에서 Jia Baoyu로, Jia Baoyu에서 Jia Huan으로, Jia Huan에서 Jia Mu로 전달되었습니다. 북소리가 멈추면 꽃을 손에 든 사람이 술자리를 수행해야 한다.
북을 치고 꽃을 피우는 것은 책임 사슬 모델의 적용입니다. 책임 사슬은 직선, 사슬 또는 트리 구조의 일부일 수 있습니다.
책임 모델의 사슬 구조
책임 패턴 체인의 가장 간단한 구현이 아래에 사용됩니다.
책임 사슬 모델과 관련된 역할은 다음과 같습니다.
● 추상 핸들러(Handler) 역할: 요청을 처리하기 위한 인터페이스를 정의합니다. 필요한 경우 인터페이스는 다음 인터페이스에 대한 참조를 설정하고 반환하는 메서드를 정의할 수 있습니다. 이 역할은 일반적으로 Java 추상 클래스 또는 Java 인터페이스에 의해 구현됩니다. 위 그림에서 Handler 클래스의 집계 관계는 특정 하위 클래스에 대한 참조를 다음 하위 클래스에 제공합니다. 추상 메소드인 handlerRequest()는 요청 처리 시 하위 클래스의 작업을 표준화합니다.
● 콘크리트 핸들러(ConcreteHandler) 역할: 요청을 받은 후 콘크리트 핸들러는 요청을 처리할지 아니면 다음 당사자에게 요청을 전달할지 선택할 수 있습니다. 콘크리트 프로세서는 다음 홈에 대한 참조를 보유하므로 필요한 경우 콘크리트 프로세서는 다음 홈에 액세스할 수 있습니다.
소스 코드
추상 핸들러 역할
다음과 같이 코드 코드를 복사합니다.
공개 추상 클래스 핸들러 {
/**
* 후임자 책임 객체 보유
*/
보호된 핸들러 후속자;
/**
* 요청을 처리하는 방법을 나타냅니다. 단, 이 방법은 매개변수를 전달하지 않습니다.
* 그러나 실제로 매개변수가 전달될 수 있습니다. 특정 필요에 따라 매개변수 전달 여부를 선택할 수 있습니다.
*/
공개 추상 무효 핸들 요청();
/**
* 가치 방법
*/
공개 핸들러 getSuccessor() {
후임자를 반환합니다.
}
/**
* 후속 책임 객체를 설정하는 할당 방법
*/
public void setSuccessor(핸들러 후속자) {
this.successor = 후임자;
}
}
특정 프로세서 역할
다음과 같이 코드 코드를 복사합니다.
공개 클래스 ConcreteHandler는 Handler {를 확장합니다.
/**
* 처리 방법, 요청을 처리하려면 이 방법을 호출하세요.
*/
@보수
공공 무효 핸들 요청() {
/**
* 후임책임객체가 있는지 판단
* 있는 경우 후속 담당 개체에 요청을 전달합니다.
* 그렇지 않은 경우 요청을 처리합니다.
*/
if(getSuccessor() != null)
{
System.out.println("요청을 그대로 두세요");
getSuccessor().handleRequest();
}또 다른
{
System.out.println("요청을 처리하는 중");
}
}
}
클라이언트 클래스
다음과 같이 코드 코드를 복사합니다.
공개 클래스 클라이언트 {
공개 정적 무효 메인(String[] args) {
//책임 체인을 조립합니다.
핸들러 handler1 = new ConcreteHandler();
핸들러 handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//요청 제출
handler1.handleRequest();
}
}
클라이언트는 두 개의 핸들러 객체를 생성하고 첫 번째 핸들러 객체의 다음 핸들러 객체가 두 번째 핸들러 객체이고 두 번째 핸들러 객체에는 다음 홈이 없음을 지정하는 것을 볼 수 있습니다. 그런 다음 클라이언트는 요청을 첫 번째 핸들러 객체에 전달합니다.
이 예제의 전송 논리는 매우 간단하기 때문입니다. 다음 소유자가 있는 한 처리를 위해 다음 소유자에게 전달되고, 다음 소유자가 없으면 자체적으로 처리됩니다. 따라서 첫 번째 핸들러 객체가 요청을 받은 후 두 번째 핸들러 객체에 요청을 전달합니다. 두 번째 핸들러 객체에는 홈이 없으므로 요청을 자체적으로 처리합니다. 활동 순서 다이어그램은 다음과 같습니다.
사용 시나리오
그러한 기능을 생각해 봅시다: 만찬 비용 관리를 신청하는 것입니다.
많은 기업이 이런 혜택을 누리고 있습니다. 즉, 프로젝트 팀이나 부서가 회사에 만찬 비용의 일부를 신청할 수 있으며, 이는 프로젝트 팀 구성원이나 부서 구성원을 위한 만찬을 조직하는 데 사용됩니다.
만찬 비용 신청의 일반적인 절차는 신청자가 먼저 신청서를 작성한 후 리더에게 제출하여 승인을 받는 것입니다. 신청서가 승인되면 리더는 신청자에게 승인이 이루어졌음을 통보합니다. 그런 다음 신청자는 재무 부서에 가서 수수료를 징수합니다. 승인되지 않은 경우 리더는 승인이 통과되지 않았음을 알리고 해당 문제는 취소됩니다.
각 직급의 리더마다 승인 한도가 다릅니다. 예를 들어, 프로젝트 관리자는 500위안 한도 내에서 신청서를 승인할 수 있으며, 부서 관리자는 1,000위안 한도 내에서 승인할 수 있습니다.
즉, 누군가 회식 비용을 요청하면 프로젝트 매니저, 부서장, 본부장 중 한 명이 그에 따라 요청을 처리하지만 요청한 사람은 결국 어떻게 될지 모릅니다. 일반적으로 신청자는 프로젝트 관리자에게 신청서를 제출하고 최종적으로는 총괄 관리자가 해당 요청을 처리할 수도 있습니다.
위의 기능을 실현하기 위해 책임 사슬 모델을 사용할 수 있습니다. 누군가가 만찬 비용을 요청하면 해당 요청은 프로젝트 관리자 -> 부서 관리자 -> 총괄 관리자와 같은 리더십 처리 체인에서 전달됩니다. 요청한 사람은 자신의 요청을 누가 처리할지 알 수 없으며, 각 리더는 자신의 책임 범위에 따라 요청을 처리할지 아니면 상위 리더에게 넘겨줄지 판단합니다. 전송이 끝났습니다.
각 리더의 처리를 분리하고 이를 별도의 책임 처리 개체로 구현한 다음 공통적이고 추상적인 상위 책임 개체를 제공하여 책임 체인이 클라이언트에서 동적으로 결합되어 다양한 기능 요구 사항을 달성할 수 있도록 해야 합니다. .
소스 코드
추상 핸들러 역할 클래스
다음과 같이 코드 코드를 복사합니다.
공개 추상 클래스 핸들러 {
/**
* 다음 요청을 처리하는 객체를 보유합니다.
*/
보호된 핸들러 후속자 = null;
/**
* 가치 방법
*/
공개 핸들러 getSuccessor() {
후임자를 반환합니다.
}
/**
* 요청을 처리할 다음 개체를 설정합니다.
*/
public void setSuccessor(핸들러 후속자) {
this.successor = 후임자;
}
/**
* 파티비용 신청 처리
* @param 사용자 신청자
* @param fee 신청금액
* @return 성공 또는 실패에 대한 구체적인 알림
*/
공개 추상 문자열 handlerFeeRequest(문자열 사용자, 이중 수수료);
}
특정 프로세서 역할
다음과 같이 코드 코드를 복사합니다.
공개 클래스 ProjectManager는 Handler를 확장합니다.
@보수
public String handlerFeeRequest(문자열 사용자, 이중 수수료) {
문자열 str = "";
//프로젝트 관리자의 권한은 상대적으로 작아서 500 이내만 가능합니다.
if(수수료 < 500)
{
//테스트를 위해 간단하게 유지하고 Zhang San의 요청에만 동의합니다.
if("장산".equals(사용자))
{
str = "성공: 프로젝트 관리자는 [" + 사용자 + "]의 만찬 비용에 동의합니다. 금액은 " + 수수료 + "위안"입니다.
}또 다른
{
//아무도 동의하지 않음
str = "실패: 프로젝트 관리자가 [" + 사용자 + "]의 만찬 비용에 동의하지 않습니다. 금액은 " + 수수료 + "위안"입니다.
}
}또 다른
{
//500개를 초과하면 계속해서 상위 담당자에게 전달하여 처리합니다.
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(사용자, 수수료);
}
}
str을 반환;
}
}
다음과 같이 코드 코드를 복사합니다.
공개 클래스 DeptManager는 핸들러 {를 확장합니다.
@보수
public String handlerFeeRequest(문자열 사용자, 이중 수수료) {
문자열 str = "";
//부서장의 권한은 1000 이내만 가능
if(수수료 < 1000)
{
//테스트를 위해 간단하게 유지하고 Zhang San의 요청에만 동의합니다.
if("장산".equals(사용자))
{
str = "성공: 부서 관리자가 [" + 사용자 + "]의 만찬 비용에 동의합니다. 금액은 " + 수수료 + "위안"입니다.
}또 다른
{
//아무도 동의하지 않음
str = "실패: 부서 관리자가 [" + 사용자 + "]의 만찬 비용에 동의하지 않습니다. 금액은 " + 수수료 + "위안"입니다.
}
}또 다른
{
//1000개를 초과하면 계속해서 상위 담당자에게 전달하여 처리합니다.
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(사용자, 수수료);
}
}
str을 반환;
}
}
다음과 같이 코드 코드를 복사합니다.
공개 클래스 GeneralManager는 Handler {를 확장합니다.
@보수
public String handlerFeeRequest(문자열 사용자, 이중 수수료) {
문자열 str = "";
//총지배인은 요청이 여기에 오면 처리할 수 있는 큰 권한을 가지고 있습니다.
if(수수료 >= 1000)
{
//테스트를 위해 간단하게 유지하고 Zhang San의 요청에만 동의합니다.
if("장산".equals(사용자))
{
str = "성공: 총지배인은 [" + 사용자 + "]의 저녁 식사 비용에 동의합니다. 금액은 " + 수수료 + "위안"입니다.
}또 다른
{
//아무도 동의하지 않음
str = "실패: 총지배인은 [" + 사용자 + "]의 만찬 비용에 동의하지 않습니다. 금액은 " + 수수료 + "위안"입니다.
}
}또 다른
{
//다음 처리 객체가 있으면 계속해서 전달합니다.
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(사용자, 수수료);
}
}
str을 반환;
}
}
클라이언트 클래스
다음과 같이 코드 코드를 복사합니다.
공개 클래스 클라이언트 {
공개 정적 무효 메인(String[] args) {
//먼저 책임 체인을 조립합니다.
핸들러 h1 = new GeneralManager();
핸들러 h2 = new DeptManager();
핸들러 h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);
//테스트 시작
String test1 = h3.handleFeeRequest("장산", 300);
System.out.println("test1 = " + test1);
String test2 = h3.handleFeeRequest("lee思", 300);
System.out.println("test2 = " + test2);
System.out.println("----------------------------");
String test3 = h3.handleFeeRequest("장산", 700);
System.out.println("test3 = " + test3);
String test4 = h3.handleFeeRequest("lee思", 700);
System.out.println("test4 = " + test4);
System.out.println("----------------------------");
String test5 = h3.handleFeeRequest("장산", 1500);
System.out.println("test5 = " + test5);
String test6 = h3.handleFeeRequest("lee思", 1500);
System.out.println("test6 = " + test6);
}
}
실행 결과는 다음과 같습니다.
순수하고 불순한 책임 사슬 모델
순수한 책임 사슬 모델에서는 특정 프로세서 개체가 두 가지 작업 중 하나만 선택할 수 있어야 합니다. 하나는 책임을 지고 책임을 다음 당사자에게 전달하는 것입니다. 특정 프로세서 개체가 일부 책임을 맡은 후 책임을 물려주는 것은 허용되지 않습니다.
순수 책임 체인 모델에서는 요청이 핸들러 객체에 의해 수신되어야 하며, 불순한 책임 체인 모델에서는 요청이 수신자 객체에 의해 수신되지 않을 수 있습니다.
순수 책임 사슬 모델의 실제 사례는 찾기 어렵고, 일반적으로 볼 수 있는 사례는 불순한 책임 사슬 모델의 구현입니다. 어떤 사람들은 불순한 책임 사슬이 전혀 책임 사슬 모델이 아니라고 생각하는데, 이는 말이 될 수 있습니다. 그러나 실제 시스템에서는 순수한 책임 사슬을 찾기가 어렵습니다. 책임 사슬이 불순하고 책임 사슬 모델이 아니라고 주장한다면 책임 사슬 모델은 별로 의미가 없을 것입니다.
Tomcat의 책임 사슬 모델 적용
우리 모두 알고 있듯이 Tomcat의 필터는 web.xml 파일에서 해당 구성을 만드는 것 외에도 javax.servlet.Filter 인터페이스를 구현해야 합니다.
다음과 같이 코드 코드를 복사합니다.
공개 클래스 TestFilter는 필터를 구현합니다.
public void doFilter(ServletRequest 요청, ServletResponse 응답,
FilterChain 체인)은 IOException, ServletException을 발생시킵니다.
chain.doFilter(요청, 응답);
}
공공 무효 파괴() {
}
public void init(FilterConfig filterConfig)는 ServletException을 발생시킵니다.
}
}
DEBUG 모드를 사용하여 본 결과는 다음과 같습니다.
실제로 TestFilter 클래스를 실제로 실행하기 전에 Tomcat의 많은 내부 클래스를 통과합니다. 그런데 Tomcat의 컨테이너 설정도 책임 모델의 체인입니다. 엔진에서 호스트, 컨텍스트, 래퍼까지 요청이 체인을 통해 전달됩니다. 녹색 상자로 둘러싸인 곳에 ApplicationFilterChain이라는 클래스가 있습니다. ApplicationFilterChain 클래스는 추상 프로세서 역할을 하며, 특정 프로세서 역할은 각 필터에서 수행됩니다.
첫 번째 질문은 ApplicationFilterChain이 모든 필터를 어디에 저장합니까?
대답은 ApplicationFilterChain 클래스의 ApplicationFilterConfig 개체 배열에 저장됩니다.
다음과 같이 코드 코드를 복사합니다.
/**
*필터.
*/
개인 ApplicationFilterConfig[] 필터 =
새로운 ApplicationFilterConfig[0];
그러면 ApplicationFilterConfig 개체는 무엇입니까?
ApplicationFilterConfig는 필터 컨테이너입니다. 다음은 ApplicationFilterConfig 클래스의 선언입니다.
다음과 같이 코드 코드를 복사합니다.
/**
* 다음에서 유용한 <code>javax.servlet.FilterConfig</code> 구현
* 웹 애플리케이션 실행 시 인스턴스화된 필터 인스턴스 관리
* 처음 시작되었습니다.
*
* @author 크레이그 R. 맥클라나한
* @version $Id: ApplicationFilterConfig.java 1201569 2011-11-14 01:36:07Z kkolinko $
*/
ApplicationFilterConfig는 웹 애플리케이션이 처음 시작될 때 자동으로 인스턴스화되며 웹 애플리케이션의 web.xml 파일에서 구성된 필터 정보를 읽어 컨테이너에 로드합니다.
방금 ApplicationFilterChain 클래스에서 생성된 ApplicationFilterConfig 배열의 길이가 0인 것을 확인했습니다. 언제 재할당되었나요?
다음과 같이 코드 코드를 복사합니다.
개인 ApplicationFilterConfig[] 필터 =
새로운 ApplicationFilterConfig[0];
ApplicationFilterChain 클래스의 addFilter() 메소드를 호출할 때입니다.
다음과 같이 코드 코드를 복사합니다.
/**
* 체인의 현재 필터 수를 제공하는 int입니다.
*/
개인 int n = 0;
공개 정적 최종 int INCREMENT = 10;
다음과 같이 코드 코드를 복사합니다.
void addFilter(ApplicationFilterConfig filterConfig) {
// 동일한 필터가 여러 번 추가되는 것을 방지합니다.
for(ApplicationFilterConfig 필터:필터)
if(필터==filterConfig)
반품;
if (n == 필터 길이) {
ApplicationFilterConfig[] newFilters =
새로운 ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
필터 = newFilters;
}
필터[n++] = filterConfig;
}
n 변수는 현재 필터 체인의 필터 수를 기록하는 데 사용됩니다. 기본적으로 n은 0과 같고 ApplicationFilterConfig 객체 배열의 길이도 0과 같으므로 addFilter() 메서드가 호출됩니다. 처음에는 (n ==filters.length)가 true이고 ApplicationFilterConfig 배열의 길이가 변경된 경우입니다. 그런 다음 필터[n++] = filterConfig; 변수 filterConfig를 ApplicationFilterConfig 배열에 넣고 현재 필터 체인의 필터 수에 1을 추가합니다.
그러면 ApplicationFilterChain의 addFilter() 메서드는 어디에서 호출됩니까?
이는 ApplicationFilterFactory 클래스의 createFilterChain() 메서드에 있습니다.
다음과 같이 코드 코드를 복사합니다.
공개 ApplicationFilterChain createFilterChain
(ServletRequest 요청, 래퍼 래퍼, 서블릿 서블릿) {
// 디스패처 유형을 가져옵니다.
DispatcherType 디스패처 = null;
if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
디스패처 = (DispatcherType) request.getAttribute(DISPATCHER_TYPE_ATTR);
}
문자열 요청 경로 = null;
객체 속성 = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
if (속성 != null){
requestPath = attribute.toString();
}
// 실행할 서블릿이 없으면 null을 반환
if (서블릿 == null)
반환(널);
부울 혜성 = 거짓;
// 필터 체인 객체 생성 및 초기화
ApplicationFilterChain filterChain = null;
if (요청 인스턴스 요청) {
요청 req = (요청) 요청;
혜성 = req.isComet();
if (Globals.IS_SECURITY_ENABLED) {
// 보안: 재활용하지 않음
filterChain = 새로운 ApplicationFilterChain();
만약 (혜성) {
req.setFilterChain(filterChain);
}
} 또 다른 {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = 새로운 ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} 또 다른 {
//디스패처 사용 요청
filterChain = 새로운 ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.set지원
(((StandardWrapper)wrapper).getInstanceSupport());
// 이 컨텍스트에 대한 필터 매핑을 획득합니다.
StandardContext 컨텍스트 = (StandardContext) Wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// 필터 매핑이 없으면 완료됩니다.
if ((filterMaps == null) || (filterMaps.length == 0))
반환(filterChain);
// 필터 매핑을 일치시키는 데 필요한 정보를 얻습니다.
문자열 servletName = 래퍼.getName();
// 이 필터 체인에 관련 경로 매핑 필터를 추가합니다.
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,디스패처)) {
계속하다;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
계속하다;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - 로그 구성 문제
계속하다;
}
부울 isCometFilter = false;
만약 (혜성) {
노력하다 {
isCometFilter = filterConfig.getFilter() CometFilter 인스턴스;
} 잡기(예외 e) {
// 참고: getFilter에는 많은 정보가 있으므로 try catch가 있습니다.
// 예외가 선언되었습니다. 그러나 필터가 많이 할당되었습니다.
// 더 일찍
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} 또 다른 {
filterChain.addFilter(filterConfig);
}
}
// 두 번째 서블릿 이름과 일치하는 필터를 추가합니다.
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
계속하다;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
계속하다;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - 로그 구성 문제
계속하다;
}
부울 isCometFilter = false;
만약 (혜성) {
노력하다 {
isCometFilter = filterConfig.getFilter() CometFilter 인스턴스;
} 잡기(예외 e) {
// 참고: getFilter에는 많은 정보가 있으므로 try catch가 있습니다.
// 예외가 선언되었습니다. 그러나 필터가 많이 할당되었습니다.
// 더 일찍
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} 또 다른 {
filterChain.addFilter(filterConfig);
}
}
// 완성된 필터 체인을 반환합니다.
반환(filterChain);
}
위 코드는 51행 앞의 첫 번째 섹션과 51행 뒤의 두 번째 섹션으로 나눌 수 있습니다.
첫 번째 단락의 주요 목적은 ApplicationFilterChain 개체를 만들고 일부 매개 변수를 설정하는 것입니다.
두 번째 단락의 주요 목적은 컨텍스트에서 모든 필터 정보를 얻은 다음 for 루프를 사용하여 filterChain.addFilter(filterConfig)를 탐색하고 호출하는 것입니다. ApplicationFilterChain 개체의 ApplicationFilterConfig 배열에 filterConfig를 넣습니다.
그러면 ApplicationFilterFactory 클래스의 createFilterChain() 메서드는 어디에서 호출됩니까?
이는 StandardWrapperValue 클래스의 호출() 메소드에서 호출됩니다.
Invoke() 메소드가 길어서 생략된 곳이 많습니다.
다음과 같이 코드 코드를 복사합니다.
공개 최종 무효 호출(요청 요청, 응답 응답)
IOException 발생, ServletException {
...중간 코드 생략 // 이 요청에 대한 필터 체인 생성
ApplicationFilterFactory 팩토리 =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain =
Factory.createFilterChain(요청, 래퍼, 서블릿);
...중간 코드 생략
filterChain.doFilter(request.getRequest(), response.getResponse());
...중간 코드 생략
}
일반적인 프로세스는 다음과 같아야 합니다.
StandardWrapperValue 클래스의 Invoke() 메소드에서 ApplicationFilterChai 클래스의 createFilterChain() 메소드를 호출합니다. ---> ApplicationFilterChai 클래스의 createFilterChain() 메소드에서 ApplicationFilterChain 클래스의 addFilter() 메소드를 호출합니다. ---> ApplicationFilterChain 클래스의 addFilter() 메서드 ApplicationFilterConfig 배열에 값을 할당합니다.
위의 코드에 따르면 StandardWrapperValue 클래스의 Invoke() 메소드는 createFilterChain() 메소드 실행 이후 ApplicationFilterChain 클래스의 doFilter() 메소드를 계속해서 실행한 후, InternalDoFilter() 메소드를 실행하는 것을 알 수 있다. doFilter() 메서드에서 호출됩니다.
다음은 InternalDoFilter() 메소드 코드의 일부입니다.
다음과 같이 코드 코드를 복사합니다.
// 필터가 있으면 다음 필터를 호출합니다.
if (pos < n) {
//다음 필터를 가져오고 포인터를 한 위치 아래로 이동합니다.
//pos 현재 ApplicationFilterChain(현재 필터 체인)이 실행하는 필터를 식별합니다.
ApplicationFilterConfig filterConfig = 필터[pos++];
필터 필터 = null;
노력하다 {
//현재 가리키는 필터의 인스턴스를 가져옵니다.
필터 = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
필터, 요청, 응답);
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
부울.FALSE);
}
if(Globals.IS_SECURITY_ENABLED) {
최종 ServletRequest req = 요청;
최종 ServletResponse res = 응답;
교장선생님 =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege
("doFilter", 필터, classType, args, 주체);
} 또 다른 {
//Filter의 doFilter() 메소드를 호출합니다.
filter.doFilter(요청, 응답, this);
}
여기서 filter.doFilter(request, response, this);는 앞서 만든 TestFilter에서 doFilter() 메서드를 호출하는 것입니다. TestFilter의 doFilter() 메소드는 계속해서 chain.doFilter(request, response); 메소드를 호출하고 이 체인은 실제로 ApplicationFilterChain이므로 호출 프로세스는 다시 dofilter를 호출하고 위의 InternalDoFilter 메소드를 호출합니다. 내부 필터가 모두 실행될 때까지 실행이 계속됩니다.
두 개의 필터가 정의된 경우 디버그 결과는 다음과 같습니다.