001/* 002 * Copyright 2002-2016 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; 023 024/** 025 * Abstract {@link org.springframework.aop.TargetSource} implementation that 026 * wraps a refreshable target object. Subclasses can determine whether a 027 * refresh is required, and need to provide fresh target objects. 028 * 029 * <p>Implements the {@link Refreshable} interface in order to allow for 030 * explicit control over the refresh status. 031 * 032 * @author Rod Johnson 033 * @author Rob Harrop 034 * @author Juergen Hoeller 035 * @since 2.0 036 * @see #requiresRefresh() 037 * @see #freshTarget() 038 */ 039public abstract class AbstractRefreshableTargetSource implements TargetSource, Refreshable { 040 041 /** Logger available to subclasses */ 042 protected final Log logger = LogFactory.getLog(getClass()); 043 044 protected Object targetObject; 045 046 private long refreshCheckDelay = -1; 047 048 private long lastRefreshCheck = -1; 049 050 private long lastRefreshTime = -1; 051 052 private long refreshCount = 0; 053 054 055 /** 056 * Set the delay between refresh checks, in milliseconds. 057 * Default is -1, indicating no refresh checks at all. 058 * <p>Note that an actual refresh will only happen when 059 * {@link #requiresRefresh()} returns {@code true}. 060 */ 061 public void setRefreshCheckDelay(long refreshCheckDelay) { 062 this.refreshCheckDelay = refreshCheckDelay; 063 } 064 065 066 @Override 067 public synchronized Class<?> getTargetClass() { 068 if (this.targetObject == null) { 069 refresh(); 070 } 071 return this.targetObject.getClass(); 072 } 073 074 /** 075 * Not static. 076 */ 077 @Override 078 public boolean isStatic() { 079 return false; 080 } 081 082 @Override 083 public final synchronized Object getTarget() { 084 if ((refreshCheckDelayElapsed() && requiresRefresh()) || this.targetObject == null) { 085 refresh(); 086 } 087 return this.targetObject; 088 } 089 090 /** 091 * No need to release target. 092 */ 093 @Override 094 public void releaseTarget(Object object) { 095 } 096 097 098 @Override 099 public final synchronized void refresh() { 100 logger.debug("Attempting to refresh target"); 101 102 this.targetObject = freshTarget(); 103 this.refreshCount++; 104 this.lastRefreshTime = System.currentTimeMillis(); 105 106 logger.debug("Target refreshed successfully"); 107 } 108 109 @Override 110 public synchronized long getRefreshCount() { 111 return this.refreshCount; 112 } 113 114 @Override 115 public synchronized long getLastRefreshTime() { 116 return this.lastRefreshTime; 117 } 118 119 120 private boolean refreshCheckDelayElapsed() { 121 if (this.refreshCheckDelay < 0) { 122 return false; 123 } 124 125 long currentTimeMillis = System.currentTimeMillis(); 126 127 if (this.lastRefreshCheck < 0 || currentTimeMillis - this.lastRefreshCheck > this.refreshCheckDelay) { 128 // Going to perform a refresh check - update the timestamp. 129 this.lastRefreshCheck = currentTimeMillis; 130 logger.debug("Refresh check delay elapsed - checking whether refresh is required"); 131 return true; 132 } 133 134 return false; 135 } 136 137 138 /** 139 * Determine whether a refresh is required. 140 * Invoked for each refresh check, after the refresh check delay has elapsed. 141 * <p>The default implementation always returns {@code true}, triggering 142 * a refresh every time the delay has elapsed. To be overridden by subclasses 143 * with an appropriate check of the underlying target resource. 144 * @return whether a refresh is required 145 */ 146 protected boolean requiresRefresh() { 147 return true; 148 } 149 150 /** 151 * Obtain a fresh target object. 152 * <p>Only invoked if a refresh check has found that a refresh is required 153 * (that is, {@link #requiresRefresh()} has returned {@code true}). 154 * @return the fresh target object 155 */ 156 protected abstract Object freshTarget(); 157 158}