001/* 002 * Copyright 2002-2019 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.jmx.support; 018 019import javax.management.MBeanServer; 020import javax.management.MBeanServerFactory; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.beans.factory.DisposableBean; 026import org.springframework.beans.factory.FactoryBean; 027import org.springframework.beans.factory.InitializingBean; 028import org.springframework.jmx.MBeanServerNotFoundException; 029import org.springframework.lang.Nullable; 030 031/** 032 * {@link FactoryBean} that obtains a {@link javax.management.MBeanServer} reference 033 * through the standard JMX 1.2 {@link javax.management.MBeanServerFactory} 034 * API. 035 * 036 * <p>Exposes the {@code MBeanServer} for bean references. 037 * 038 * <p>By default, {@code MBeanServerFactoryBean} will always create 039 * a new {@code MBeanServer} even if one is already running. To have 040 * the {@code MBeanServerFactoryBean} attempt to locate a running 041 * {@code MBeanServer} first, set the value of the 042 * "locateExistingServerIfPossible" property to "true". 043 * 044 * @author Rob Harrop 045 * @author Juergen Hoeller 046 * @since 1.2 047 * @see #setLocateExistingServerIfPossible 048 * @see #locateMBeanServer 049 * @see javax.management.MBeanServer 050 * @see javax.management.MBeanServerFactory#findMBeanServer 051 * @see javax.management.MBeanServerFactory#createMBeanServer 052 * @see javax.management.MBeanServerFactory#newMBeanServer 053 * @see MBeanServerConnectionFactoryBean 054 * @see ConnectorServerFactoryBean 055 */ 056public class MBeanServerFactoryBean implements FactoryBean<MBeanServer>, InitializingBean, DisposableBean { 057 058 protected final Log logger = LogFactory.getLog(getClass()); 059 060 private boolean locateExistingServerIfPossible = false; 061 062 @Nullable 063 private String agentId; 064 065 @Nullable 066 private String defaultDomain; 067 068 private boolean registerWithFactory = true; 069 070 @Nullable 071 private MBeanServer server; 072 073 private boolean newlyRegistered = false; 074 075 076 /** 077 * Set whether or not the {@code MBeanServerFactoryBean} should attempt 078 * to locate a running {@code MBeanServer} before creating one. 079 * <p>Default is {@code false}. 080 */ 081 public void setLocateExistingServerIfPossible(boolean locateExistingServerIfPossible) { 082 this.locateExistingServerIfPossible = locateExistingServerIfPossible; 083 } 084 085 /** 086 * Set the agent id of the {@code MBeanServer} to locate. 087 * <p>Default is none. If specified, this will result in an 088 * automatic attempt being made to locate the attendant MBeanServer, 089 * and (importantly) if said MBeanServer cannot be located no 090 * attempt will be made to create a new MBeanServer (and an 091 * MBeanServerNotFoundException will be thrown at resolution time). 092 * <p>Specifying the empty String indicates the platform MBeanServer. 093 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 094 */ 095 public void setAgentId(String agentId) { 096 this.agentId = agentId; 097 } 098 099 /** 100 * Set the default domain to be used by the {@code MBeanServer}, 101 * to be passed to {@code MBeanServerFactory.createMBeanServer()} 102 * or {@code MBeanServerFactory.findMBeanServer()}. 103 * <p>Default is none. 104 * @see javax.management.MBeanServerFactory#createMBeanServer(String) 105 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 106 */ 107 public void setDefaultDomain(String defaultDomain) { 108 this.defaultDomain = defaultDomain; 109 } 110 111 /** 112 * Set whether to register the {@code MBeanServer} with the 113 * {@code MBeanServerFactory}, making it available through 114 * {@code MBeanServerFactory.findMBeanServer()}. 115 * <p>Default is {@code true}. 116 * @see javax.management.MBeanServerFactory#createMBeanServer 117 * @see javax.management.MBeanServerFactory#findMBeanServer 118 */ 119 public void setRegisterWithFactory(boolean registerWithFactory) { 120 this.registerWithFactory = registerWithFactory; 121 } 122 123 124 /** 125 * Creates the {@code MBeanServer} instance. 126 */ 127 @Override 128 public void afterPropertiesSet() throws MBeanServerNotFoundException { 129 // Try to locate existing MBeanServer, if desired. 130 if (this.locateExistingServerIfPossible || this.agentId != null) { 131 try { 132 this.server = locateMBeanServer(this.agentId); 133 } 134 catch (MBeanServerNotFoundException ex) { 135 // If agentId was specified, we were only supposed to locate that 136 // specific MBeanServer; so let's bail if we can't find it. 137 if (this.agentId != null) { 138 throw ex; 139 } 140 logger.debug("No existing MBeanServer found - creating new one"); 141 } 142 } 143 144 // Create a new MBeanServer and register it, if desired. 145 if (this.server == null) { 146 this.server = createMBeanServer(this.defaultDomain, this.registerWithFactory); 147 this.newlyRegistered = this.registerWithFactory; 148 } 149 } 150 151 /** 152 * Attempt to locate an existing {@code MBeanServer}. 153 * Called if {@code locateExistingServerIfPossible} is set to {@code true}. 154 * <p>The default implementation attempts to find an {@code MBeanServer} using 155 * a standard lookup. Subclasses may override to add additional location logic. 156 * @param agentId the agent identifier of the MBeanServer to retrieve. 157 * If this parameter is {@code null}, all registered MBeanServers are 158 * considered. 159 * @return the {@code MBeanServer} if found 160 * @throws org.springframework.jmx.MBeanServerNotFoundException 161 * if no {@code MBeanServer} could be found 162 * @see #setLocateExistingServerIfPossible 163 * @see JmxUtils#locateMBeanServer(String) 164 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 165 */ 166 protected MBeanServer locateMBeanServer(@Nullable String agentId) throws MBeanServerNotFoundException { 167 return JmxUtils.locateMBeanServer(agentId); 168 } 169 170 /** 171 * Create a new {@code MBeanServer} instance and register it with the 172 * {@code MBeanServerFactory}, if desired. 173 * @param defaultDomain the default domain, or {@code null} if none 174 * @param registerWithFactory whether to register the {@code MBeanServer} 175 * with the {@code MBeanServerFactory} 176 * @see javax.management.MBeanServerFactory#createMBeanServer 177 * @see javax.management.MBeanServerFactory#newMBeanServer 178 */ 179 protected MBeanServer createMBeanServer(@Nullable String defaultDomain, boolean registerWithFactory) { 180 if (registerWithFactory) { 181 return MBeanServerFactory.createMBeanServer(defaultDomain); 182 } 183 else { 184 return MBeanServerFactory.newMBeanServer(defaultDomain); 185 } 186 } 187 188 189 @Override 190 @Nullable 191 public MBeanServer getObject() { 192 return this.server; 193 } 194 195 @Override 196 public Class<? extends MBeanServer> getObjectType() { 197 return (this.server != null ? this.server.getClass() : MBeanServer.class); 198 } 199 200 @Override 201 public boolean isSingleton() { 202 return true; 203 } 204 205 206 /** 207 * Unregisters the {@code MBeanServer} instance, if necessary. 208 */ 209 @Override 210 public void destroy() { 211 if (this.newlyRegistered) { 212 MBeanServerFactory.releaseMBeanServer(this.server); 213 } 214 } 215 216}