How to add custom endpoints for executable jar - java

I have an executable jar developed using spring 3. It periodically performs some task using #Scheduled annotation and generates the data, mainly counters. Now I want to display these counters for monitoring and analysis purposes, similar to what spring boot provides here. I cannot use spring boot as it needs spring 4 and my jar has dependencies those use spring 3.
Here is my #configuration class:
/**
* Requester - The main entry point for this application.
*
*/
#Configuration
#ComponentScan(basePackages = "com.tpv.req")
#EnableScheduling
#ImportResource({ "classpath:/spring/applicationContext-common.xml" })
#PropertySource(value="file:/opt/requester/requester.properties")
public class Requester implements SchedulingConfigurer {
protected static final Logger logger = LoggerFactory.getLogger(Requester.class);
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(1);
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
return pspc;
}
#SuppressWarnings({ "unused", "resource" })
public static void main(String args[]) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext(Requester.class);
}
}
#Component class :
#Component
public class CustomRequester {
#Scheduled(initialDelay = 5000, fixedDelayString = "${requester.wait.time}")
public void processRequests() {
//Perform some task
}
Tried with #Controller :
#Controller
#RequestMapping("/status")
public class StatusController {
#Autowired
Status status;
/**
* #return Status object (as json)
*/
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody Status doResponse() {
return status;
}
}
This did not work.
Is there any way I can have similar endpoints without spring boot? Or how can I display these counters? Can using embedded jetty serve the purpose?
Thank you.

I figured it out. Embedding jetty can easily resolve the issue. Refactored my code a little bit, in terms of separation of config classes from main class and started jetty server from main.
Here goes the code:
public class ScannerStartup {
private static Logger logger = LoggerFactory.getLogger(ScannerStartup.class);
private static final int DEFAULT_PORT = 8080;
private static final String CONTEXT_PATH = "/";
// Package of the config class
private static final String CONFIG_LOCATION = "com.tpv.req.config";
private static final String MAPPING_URL = "/*";
public static void main(String args[]) throws Exception {
startJetty(getPortFromArgs(args));
}
private static int getPortFromArgs(String[] args) {
if (args.length > 0) {
try {
return Integer.valueOf(args[0]);
} catch (NumberFormatException ignore) {
}
}
logger.debug("No server port configured, falling back to {}", DEFAULT_PORT);
return DEFAULT_PORT;
}
private static void startJetty(int port) throws Exception {
Server server = new Server(port);
server.setHandler(getServletContextHandler(getContext()));
server.start();
logger.info("Server started at port {}", port);
server.join();
}
private static ServletContextHandler getServletContextHandler(WebApplicationContext context) throws IOException {
ServletContextHandler contextHandler = new ServletContextHandler();
contextHandler.setErrorHandler(null);
contextHandler.setContextPath(CONTEXT_PATH);
contextHandler.addServlet(new ServletHolder(new DispatcherServlet(context)), MAPPING_URL);
contextHandler.addEventListener(new ContextLoaderListener(context));
return contextHandler;
}
private static WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setConfigLocation(CONFIG_LOCATION);
return context;
}
}
Config classes: I separated them out as AppConfig and WebConfig
#Configuration
#ComponentScan(basePackages = "com.tpv.req")
#EnableScheduling
#PropertySource(value = "file:/opt/scanner-application.properties")
public class AppConfig implements SchedulingConfigurer {
protected static final Logger logger = LoggerFactory.getLogger(AppConfig.class);
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
#Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(1);
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
return pspc;
}
}
WebMvcConfig class:
#Configuration
#ComponentScan(basePackages = "com.tpv.req.controller")
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {`enter code here`
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
converter.setObjectMapper(objectMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
}
The main method in ScannerStartup class will load application context and config classes and these in turn will load the components specified in your project and it will run jetty server at the port provided through command line. If none provided , it will use default port 8080.
Here is an example of controller class:
#Controller
#RequestMapping("/status")
public class ScannerStatusController {
#Autowired
ScannerStatus status;
/**
* #return Status object (as json)
*/
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody ScannerStatus doResponse() {
return status;
}
}
just start the application with:
java -jar {jarname}.jar
This controller will display 'status' object in json format when you hit:
localhost:8080/status

Related

Prototyped bean not triggering Scheduled method in Spring Boot

I'm using Java 17, spring-boot 2.7.3 and spring 5.3.22 dependencies.
I have prototyped beans as follows:
#Service
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class InsertTransactionDetailsByScheduleAPIInteractor
implements InsertTransactionDetailsByScheduleAPIInputBoundary {
private final InsertTransactionsInputBoundary insertTransactionsInputBoundary;
private final RetrieveFileFromSecureFileTransferProtocolInputBoundary retrieveFileFromSecureFileTransferProtocolInputBoundary;
public InsertTransactionDetailsByScheduleAPIInteractor(
final InsertTransactionsInputBoundary insertTransactionsInputBoundaryParam,
#Qualifier(Constants.PROTOTYPE_RETRIEVE_FILE_BEAN_QUALIFIER) final RetrieveFileFromSecureFileTransferProtocolInputBoundary retrieveFileFromSecureFileTransferProtocolInputBoundaryParam) {
super();
this.insertTransactionsInputBoundary = insertTransactionsInputBoundaryParam;
this.retrieveFileFromSecureFileTransferProtocolInputBoundary = retrieveFileFromSecureFileTransferProtocolInputBoundaryParam;
}
/**
* {#inheritDoc}
*/
#Override
// #Scheduled(cron = "* 30 1 * * *", zone = "America/Sao_Paulo")
#Scheduled(initialDelay = 5, fixedRate = 1, timeUnit = TimeUnit.SECONDS)
public void insertTransactionsBySchedule() throws Exception {
this.insertTransactionsInputBoundary.insertTransactions(LocalDate.now(Constants.DEFAULT_ZONE_ID),
this.retrieveFileFromSecureFileTransferProtocolInputBoundary);
}
}
#Configuration
#RefreshScope
class FTPConfiguration {
private final ConsulProperties consulProperties;
public FTPConfiguration(final ConsulProperties consulPropertiesParam) {
super();
this.consulProperties = consulPropertiesParam;
}
#Bean
#RequestScope
#Primary
RetrieveFileFromSecureFileTransferProtocolInputBoundary createRequestScopedRetrieveFileFromSecureFileTransferProtocolBean()
throws Exception {
return this.createRetrieveFileFromSecureFileTransferProtocolBean(true);
}
#Bean
#RequestScope
#Primary
ChannelSftp createRequestScopedSecureFileTransferProtocolChannel() throws JSchException {
return this.createSFTPChannel(true);
}
#Bean(destroyMethod = Constants.FTP_SESSION_BEAN_DESTROY_METHOD)
#RequestScope
#Primary
Session createRequestScopeSecureFileTransferProtocolSession() throws JSchException {
return this.createSFTPSession();
}
#Bean(Constants.PROTOTYPE_RETRIEVE_FILE_BEAN_QUALIFIER)
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
RetrieveFileFromSecureFileTransferProtocolInputBoundary createPrototypeScopedRetrieveFileFromSecureFileTransferProtocolBean()
throws Exception {
return this.createRetrieveFileFromSecureFileTransferProtocolBean(false);
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
ChannelSftp createPrototypeScopedSecureFileTransferProtocolChannel() throws JSchException {
return this.createSFTPChannel(false);
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Session createPrototypeScopedSecureFileTransferProtocolSession() throws JSchException {
return this.createSFTPSession();
}
private RetrieveFileFromSecureFileTransferProtocolInputBoundary createRetrieveFileFromSecureFileTransferProtocolBean(
final boolean isRequestScope) throws Exception {
final var channelSFTP = isRequestScope ? this.createRequestScopedSecureFileTransferProtocolChannel()
: this.createPrototypeScopedSecureFileTransferProtocolChannel();
return new RetrieveFileFromSecureFileTransferProtocolInteractor(channelSFTP,
new ListDirFilesFromSecureFileTransferProtocolInteractor(channelSFTP));
}
private ChannelSftp createSFTPChannel(final boolean isRequestScope) throws JSchException {
final var channel = (isRequestScope ? this.createRequestScopeSecureFileTransferProtocolSession()
: this.createPrototypeScopedSecureFileTransferProtocolSession()).openChannel("sftp");
channel.connect(this.consulProperties.getChannelTimeout());
return (ChannelSftp) channel;
}
private Session createSFTPSession() throws JSchException {
final var session = new JSch().getSession(this.consulProperties.getUsername(), this.consulProperties.getHost(),
this.consulProperties.getPort());
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(this.consulProperties.getFtpPassword());
session.connect(this.consulProperties.getSessionTimeout());
return session;
}
}
My application class:
#SpringBootApplication
#EnableCaching
#EnableScheduling
public class Application implements Closeable {
private static ConfigurableApplicationContext run;
public static void main(final String[] args) {
Application.run = SpringApplication.run(Application.class, args);
}
#Override
public void close() {
Application.run.close();
}
}
I annotated the InsertTransactionDetailsByScheduleAPIInteractor also as prototype in order to have a new instance of the inner beans per schedule execution, but somehow the #Scheduled method only runs when I have a singleton InsertTransactionDetailsByScheduleAPIInteractor bean, which in my use case I can't have, otherwise I wouldn't close FTP connection. I know before Spring 4.3, #Scheduled methods only works with Singleton beans, but as mentioned before I'm using Spring version 5.3.22.
You are using Spring but that doesn't mean everything has to be managed by Spring. There is nothing wrong with opening an SFTP Session inside your class when you need it and close it afterwards. You can probably even use a try-with-resources as I expect the Session to be a AutoClosable which can be used.
So in short manually create the objects you need inside your scheduled job and cleanup after the job finished. This way your scheduler can be a regular singleton and properly cleanup after itself.

Spring MVC Pass Bean Object to RestController from embedded Tomcat

I am building a REST API into an existing Spring Java application and I am not sure how to pass the Bean to the Rest Controller from the Main part of the app.
I would like to be able to have the Bean IDao created with its database instance passed into the UserController so it can be used as shown below.
As is, it is not able to autowire the Bean into the UserController. If I change the ComponentScan to include the main package it will autowire but not without ending up in and infinite Bean creation loop. What am I doing wrong?
package com.app.main;
public class App {
private static AnnotationConfigApplicationContext ctx;
public static void main(String[] args) throws Exception {
ctx = new AnnotationConfigApplicationContext(RestApiConfig.class);
}
}
package com.app.main;
#Configuration
public class RestApiConfig {
#Bean
public IDao<User> userDao(Database database) {
return new DatabaseDao<>(database, User.class);
}
#Bean
public Database database() {
return new Database();
}
#Bean
public RestApi restApi(IDao<User> userDao) {
return new RestApi(userDao);
}
package com.app.rest;
public class RestApi {
private final int PORT = 8080;
private final IDao<User> userDao;
public RestApi( IDao<User> userDao) {
this.userDao = userDao;
run();
}
public void run() {
String contextPath = "/api";
String webappDir = new File("src/main/webapp").getAbsolutePath();
Tomcat tomcat = new Tomcat(); // Tomcat 9.x.x
tomcat.setPort(PORT);
tomcat.getConnector(); // Trigger the creation of the default connector
Context context = tomcat.addWebapp(contextPath, webappDir);
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
tomcat.getServer().await();
}
}
package com.app.rest;
#Configuration
#EnableWebMvc
#ComponentScan({"com.app.rest"})
public class RestApiServletConfig {
}
package com.app.rest;
public class RestApiServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ RestApiServletConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
}
package com.app.rest;
#RestController
public class UserController {
private final IDao<User> repository;
UserController(IDao<User> repository) {
this.repository = repository;
}
#GetMapping("/users/{id}")
public User userById(#PathVariable Long id) {
return repository.get(id);
}
}

In Spring Boot which class would be initialize first #Component or #Configuration

I have a class annotated with #Component which is use to initialze application.yml config properties. Service classe is using configuration property. But sometime my Service class instance created before the Configuration class and I get null property value in service class, Its random not specific pattern.
Configuration Initializer class..
#Component
public class ConfigInitializer implements InitializingBean {
private static final Logger log = LoggerFactory.getLogger(ConfigInitializer.class);
#Autowired
ProxyConfig proxyConfig;
/*#PostConstruct
public void postConstruct(){
setProperties();
}
*/
#Override
public void afterPropertiesSet() {
setProperties();
}
private void setSystemProperties(){
log.debug("Setting properties...");
Properties props = new Properties();
props.put("PROXY_URL", proxyConfig.getProxyUrl());
props.put("PROXY_PORT", proxyConfig.getProxyPort());
System.getProperties().putAll(props);
}
}
#Component
#ConfigurationProperties(prefix = "proxy-config")
public static class ProxyConfig {
private String proxyUrl;
private String proxyPort;
public String getProxyUrl() {
return proxyUrl;
}
public void setProxyUrl(String proxyUrl) {
this.proxyUrl = proxyUrl;
}
public String getProxyPort() {
return proxyPort;
}
public void setProxyPort(String proxyPort) {
this.proxyPort = proxyPort;
}
}
Service Class..
#Service("receiverService")
public class ReceiverService {
private static final Logger logger = LoggerFactory.getLogger(ReceiverService.class);
private ExecutorService executorService = Executors.newSingleThreadExecutor();
#Autowired
public ReceiverService() {
initClient();
}
private void initClient() {
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
String value = System.getProperty("PROXY_URL"); **//Here I am getting null**
logger.info("Values : " + value);
}
});
System.out.println("future.get() = " + future.get());
}
}
Above Service class get null values String value = System.getProperty("PROXY_URL")
When I use #DependsOn annotation on Service class, it works fine.
In my little knowledge, I know Spring does not have specific order of bean creation.
I want to know If I use #Configuration instead of #Component on ConfigInitializer class like below, Will spring initialize ConfigInitializer
class before other beans ?.
#Configuration
public class ConfigInitializer implements InitializingBean {
//code here
}

Jersey Test #Autowired field in tested class is null

I have a little problem. I think this is typical question. However, I can't find good example. My application is using Jersey. And I want to test controller by client as test. Controller has private field - StudentService. When I debug test I see, that field is null. This leads to error. And I need to inject this field. I tried this:
My Controller
#Path("/student")
#Component
public class StudentResourse {
#Autowired
private StrudentService service; // this field Spring does not set
#Path("/getStudent/{id}")
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Student getStudent(#PathParam("id") long id) {
return service.get(id);
}
}
My JUnit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:config.xml")
#TestExecutionListeners({ DbUnitTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
public class StudentResourseTest extends JerseyTest {
private static final String PACKAGE_NAME = "com.example.servlet";
private static final String FILE_DATASET = "/data.xml";
#Autowired
private StudentService service; // this field is setted by Spring, but I do not need this field for test
public StudentResourseTest() {
super(new WebAppDescriptor.Builder(PACKAGE_NAME).build());
}
#Override
protected TestContainerFactory getTestContainerFactory() {
return new HTTPContainerFactory();
}
#Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("restful.server.resource")
.contextParam("contextConfigLocation",
"classpath:/config.xml").contextPath("/")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class).build();
}
#Test
#DatabaseSetup(FILE_DATASET)
public void test() throws UnsupportedEncodingException {
ClientResponse response = resource().path("student").path("getStudent")
.path("100500").accept(MediaType.APPLICATION_XML)
.get(ClientResponse.class);
Student student = (Student) response.getEntity(Student.class);
} }
I guees, that problem is in test class. Because, when I run my application not in test, I can directly request students and everything working fine. But when I test classes, internal field of Controller does not setted. How to fix this bug? Thanks for your answers.
This is in my config.xml
<context:component-scan base-package="com.example" />
<bean id="StudentResourse" class="com.example.servlet.StudentResourse">
<property name="service" ref="studentService" />
</bean>
<bean id="service" class="com.example.service.StudentServiceImpl" />
One issue may be that you're trying to configure your test application in constructor and in configure() method. Use one or another but not both because in this case your configure() method is not invoked and hence you may not be using SpringServlet and everything that is defined in this method.
Reference: https://github.com/jiunjiunma/spring-jersey-test and http://geek.riffpie.com/unit-testing-restful-jersey-services-glued-together-with-spring/
Idea is to get a hold of the application context inside jersey by using ApplicationContextAware interface. There after we can grab the exact bean already created by spring, in your case, StudentService. Below example shows a mocked version of the dependency, SampleService, used to test the resource layer apis.
Resource class delegating the processing to a service layer
#Component
#Path("/sample")
public class SampleResource {
#Autowired
private SampleService sampleService;
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path ("/{id}")
public Sample getSample(#PathParam("id") int id) {
Sample sample = sampleService.getSample(id);
if (sample == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return sample;
}
}
Service layer encapsulating business logic
#Service
public class SampleService {
private static final Map<Integer, Sample> samples = new HashMap<>();
static {
samples.put(1, new Sample(1, "sample1"));
samples.put(2, new Sample(2, "sample2"));
}
public Sample getSample(int id) {
return samples.get(id);
}
}
Unit test for the above resource
public class SampleResourceTest extends SpringContextAwareJerseyTest {
private SampleService mockSampleService;
// create mock object for our test
#Bean
static public SampleService sampleService() {
return Mockito.mock(SampleService.class);
}
/**
* Create our own resource here so only the test resource is loaded. If
* we use #ComponentScan, the whole package will be scanned and more
* resources may be loaded (which is usually NOT what we want in a test).
*/
#Bean
static public SampleResource sampleResource() {
return new SampleResource();
}
// get the mock objects from the internal servlet context, because
// the app context may get recreated for each test so we have to set
// it before each run
#Before
public void setupMocks() {
mockSampleService = getContext().getBean(SampleService.class);
}
#Test
public void testMock() {
Assert.assertNotNull(mockSampleService);
}
#Test
public void testGetSample() {
// see how the mock object hijack the sample service, now id 3 is valid
Sample sample3 = new Sample(3, "sample3");
Mockito.when(mockSampleService.getSample(3)).thenReturn(sample3);
expect().statusCode(200).get(SERVLET_PATH + "/sample/3");
String jsonStr = get(SERVLET_PATH + "/sample/3").asString();
Assert.assertNotNull(jsonStr);
}
}
SpringContextAwareJerseyTest
#Configuration
public class SpringContextAwareJerseyTest extends JerseyTest {
protected static String SERVLET_PATH = "/api";
final private static ThreadLocal<ApplicationContext> context =
new ThreadLocal<>();
protected String getResourceLocation() {
return "example.rest";
}
protected String getContextConfigLocation() {
return getClass().getName();
}
static private String getContextHolderConfigLocation() {
return SpringContextAwareJerseyTest.class.getName();
}
protected WebAppDescriptor configure() {
String contextConfigLocation = getContextConfigLocation() + " " +
getContextHolderConfigLocation();
Map<String, String> initParams = new HashMap<>();
initParams.put("com.sun.jersey.config.property.packages",
getResourceLocation());
initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true");
return new WebAppDescriptor.Builder(initParams)
.servletClass(SpringServlet.class)
.contextParam(
"contextClass",
"org.springframework.web.context.support.AnnotationConfigWebApplicationContext")
.contextParam("contextConfigLocation", contextConfigLocation)
.servletPath(SERVLET_PATH) // if not specified, it set to root resource
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
protected final ApplicationContext getContext() {
return context.get();
}
#Bean
public static ContextHolder contextHolder() {
return new ContextHolder();
}
private static class ContextHolder implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context.set(applicationContext);
}
}
}
Using the above with jersey 1.8

MBean in JMX JConsole using Spring without XML

I want to create Bean using Spring annotations and without any XML configuration. I have something like public class WebAppInitializer implements WebApplicationInitializer which load all application context.
I have my bean as a class:
#ManagedResource(objectName = "myBean.example:name=MonitoringService")
#Component
public class MonitoringService implements IMonitoringService {
public static final Logger LOG = LoggerFactory.getLogger(MonitoringService.class);
private boolean isDbServicesEnabled = true;
#ManagedAttribute(description = "DBServices configurator")
public boolean isDbServicesEnabled() {
return isDbServicesEnabled;
}
#ManagedAttribute(description = "DBServices configurator")
public void setDbServicesEnabled(boolean dbServicesEnabled) {
LOG.info("DBServices " + (isDbServicesEnabled ? "enabled" : "disabled"));
isDbServicesEnabled = dbServicesEnabled;
}
}
and simple interface:
public interface IMonitoringService {
public boolean isDbServicesEnabled();
public void setDbServicesEnabled(boolean dbServicesEnabled);
}
I deploy it to Glassfish 3 server and everything work ok, but I can not see it JConsole.
Where is the problem?
I also use SimonMXBeanManager for statistics and it wrapper works ok.
Do I have to register it in MBeanServer?
This is a class for SimonManager configuration:
#Configuration
public class MonitoringConfiguration {
#Bean
public Manager simonManager() throws Exception {
ManagerFactoryBean managerFactoryBean = new ManagerFactoryBean();
Callback jmxRegisterCallback = new JmxRegisterCallback(mBeanServer(), "myBean.example");
managerFactoryBean.setCallbacks(Lists.newArrayList(jmxRegisterCallback));
return managerFactoryBean.getObject();
}
#Bean
public SimonManagerMXBeanWrapper simonManagerMXBean() throws Exception {
return new WebApplicationSimonManagerMXBeanWrapper(new SimonManagerMXBeanImpl(simonManager()));
}
#Bean
public MBeanServer mBeanServer() {
MBeanServerFactoryBean mBeanServerFactoryBean = new MBeanServerFactoryBean();
mBeanServerFactoryBean.setLocateExistingServerIfPossible(true);
mBeanServerFactoryBean.afterPropertiesSet();
return mBeanServerFactoryBean.getObject();
}
#Bean
public AnnotationMBeanExporter annotationMBeanExporter() {
return new AnnotationMBeanExporter();
}
#ManagedResource(objectName = "myBean.example:name=SimonManager")
private class WebApplicationSimonManagerMXBeanWrapper extends SimonManagerMXBeanWrapper {
public WebApplicationSimonManagerMXBeanWrapper(SimonManagerMXBean delegate) {
super(delegate);
}
}
and a class which loads application context:
public class WebAppInitializer implements WebApplicationInitializer {
String[] locations = new String[] {
"myBean.example"
};
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(
RootContextConfig.class
);
rootContext.scan(locations);
rootContext.refresh();
container.addListener(new RequestContextListener());
container.addListener(new ContextLoaderListener(rootContext));
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(WebAppConfig.class);
ServletRegistration.Dynamic dispatcher = container.addServlet(
"dispatcher", new DispatcherServlet(dispatcherContext)
);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
createSimonWebConsole(container);
}
private void createSimonWebConsole(ServletContext container) {
ServletRegistration.Dynamic dn =
container.addServlet("simon-webconsole", new SimonConsoleServlet());
dn.setInitParameter("url-prefix", "/javasimon-console");
dn.addMapping("/javasimon-console/*");
}
}
Ok, I figured out, that I have to add #ComponentScan annotation with "myBean.example" namespace to class MonitoringConfiguration. Now I can configure my services in JConsole.

Categories