001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.aop.target.dynamic; 018 019import org.apache.commons.logging.Log; 020import org.apache.commons.logging.LogFactory; 021 022import org.springframework.aop.TargetSource; 023import org.springframework.lang.Nullable; 024 025/** 026 * Abstract {@link org.springframework.aop.TargetSource} implementation that 027 * wraps a refreshable target object. Subclasses can determine whether a 028 * refresh is required, and need to provide fresh target objects. 029 * 030 * <p>Implements the {@link Refreshable} interface in order to allow for 031 * explicit control over the refresh status. 032 * 033 * @author Rod Johnson 034 * @author Rob Harrop 035 * @author Juergen Hoeller 036 * @since 2.0 037 * @see #requiresRefresh() 038 * @see #freshTarget() 039 */ 040public abstract class AbstractRefreshableTargetSource implements TargetSource, Refreshable { 041 042 /** Logger available to subclasses. */ 043 protected final Log logger = LogFactory.getLog(getClass()); 044 045 @Nullable 046 protected Object targetObject; 047 048 private long refreshCheckDelay = -1; 049 050 private long lastRefreshCheck = -1; 051 052 private long lastRefreshTime = -1; 053 054 private long refreshCount = 0; 055 056 057 /** 058 * Set the delay between refresh checks, in milliseconds. 059 * Default is -1, indicating no refresh checks at all. 060 * <p>Note that an actual refresh will only happen when 061 * {@link #requiresRefresh()} returns {@code true}. 062 */ 063 public void setRefreshCheckDelay(long refreshCheckDelay) { 064 this.refreshCheckDelay = refreshCheckDelay; 065 } 066 067 068 @Override 069 public synchronized Class<?> getTargetClass() { 070 if (this.targetObject == null) { 071 refresh(); 072 } 073 return this.targetObject.getClass(); 074 } 075 076 /** 077 * Not static. 078 */ 079 @Override 080 public boolean isStatic() { 081 return false; 082 } 083 084 @Override 085 @Nullable 086 public final synchronized Object getTarget() { 087 if ((refreshCheckDelayElapsed() && requiresRefresh()) || this.targetObject == null) { 088 refresh(); 089 } 090 return this.targetObject; 091 } 092 093 /** 094 * No need to release target. 095 */ 096 @Override 097 public void releaseTarget(Object object) { 098 } 099 100 101 @Override 102 public final synchronized void refresh() { 103 logger.debug("Attempting to refresh target"); 104 105 this.targetObject = freshTarget(); 106 this.refreshCount++; 107 this.lastRefreshTime = System.currentTimeMillis(); 108 109 logger.debug("Target refreshed successfully"); 110 } 111 112 @Override 113 public synchronized long getRefreshCount() { 114 return this.refreshCount; 115 } 116 117 @Override 118 public synchronized long getLastRefreshTime() { 119 return this.lastRefreshTime; 120 } 121 122 123 private boolean refreshCheckDelayElapsed() { 124 if (this.refreshCheckDelay < 0) { 125 return false; 126 } 127 128 long currentTimeMillis = System.currentTimeMillis(); 129 130 if (this.lastRefreshCheck < 0 || currentTimeMillis - this.lastRefreshCheck > this.refreshCheckDelay) { 131 // Going to perform a refresh check - update the timestamp. 132 this.lastRefreshCheck = currentTimeMillis; 133 logger.debug("Refresh check delay elapsed - checking whether refresh is required"); 134 return true; 135 } 136 137 return false; 138 } 139 140 141 /** 142 * Determine whether a refresh is required. 143 * Invoked for each refresh check, after the refresh check delay has elapsed. 144 * <p>The default implementation always returns {@code true}, triggering 145 * a refresh every time the delay has elapsed. To be overridden by subclasses 146 * with an appropriate check of the underlying target resource. 147 * @return whether a refresh is required 148 */ 149 protected boolean requiresRefresh() { 150 return true; 151 } 152 153 /** 154 * Obtain a fresh target object. 155 * <p>Only invoked if a refresh check has found that a refresh is required 156 * (that is, {@link #requiresRefresh()} has returned {@code true}). 157 * @return the fresh target object 158 */ 159 protected abstract Object freshTarget(); 160 161}