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.
Related
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);
}
}
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
i'm trying to combine vaadin with spring (without spring-boot) and java-annotation based configuration for the spring part.
The autowiring seems to work on the vaadin-ui part but not in "custom-ui classes" (e.g. "public class LoginScreen extends CustomComponent"). I'm getting an NPE or a null-object on SysOut.
Further i noticed that "#ComponentScan(basePackages={"net.myapp"})" is not scanning for beans. The only way to declare beans is in the CustomConfiguration itself.
XML-Configuration is not something i prefer.
I'm following this Tutorial: Link
CustomConfiguration.java
#Configuration
#ComponentScan(basePackages={"net.myapp"})
#EnableVaadin
public class CustomConfiguration {
// this is working but i want to use componentscan!
#Bean
public String test() {
return "test...";
}
#Bean
public TestBean testBean() {
return new TestBean();
}
#Bean
public LoginScreen loginScreenBean() {
return new LoginScreen();
}
}
SpringVaadinServlet.java
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = Application.class)
#SuppressWarnings("serial")
public class SpringVaadinServlet extends VaadinServlet implements SessionInitListener {
#Autowired
protected VaadinUIProvider applicationProvider;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
AutowireCapableBeanFactory ctx = ((ApplicationContext)
getServletContext().getAttribute("applicationContext")).getAutowireCapableBeanFactory();
ctx.autowireBean(this);
}
#Override
protected void servletInitialized() {
getService().addSessionInitListener(this);
}
#Override
public void sessionInit(SessionInitEvent event) throws ServiceException {
event.getSession().addUIProvider(applicationProvider);
}
}
VaadinUIProvider.java
#SpringComponent
#SuppressWarnings("serial")
public class VaadinUIProvider extends UIProvider {
#Autowired
ApplicationContext applicationContext;
#Override
public Class<? extends UI> getUIClass(UIClassSelectionEvent event) {
return Application.class;
}
#Override
public UI createInstance(UICreateEvent event) {
UI instance = new Application();
System.out.println("applicationContext is null? " + applicationContext);
applicationContext.getAutowireCapableBeanFactory().autowireBean(instance);
return instance;
}
}
SpringApplicationContextListener.java
#WebListener
public class SpringApplicationContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CustomConfiguration.class);
sce.getServletContext().setAttribute("applicationContext", applicationContext);
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
Application.java
#Theme("mytheme1")
#SpringUI
#SuppressWarnings("serial")
public class Application extends UI {
#Autowired
private TestBean testBean;
#Autowired
private String test;
#Override
protected void init(VaadinRequest vaadinRequest) {
// working
System.out.println("init testBean: " + testBean);
System.out.println("init test: " + test);
Window window = new Window();
window.setContent(new LoginScreen());
window.setClosable(false);
window.setWidth("400px");
window.setHeight("280px");
window.setModal(true);
window.setDraggable(false);
window.setResizable(false);
window.center();
addWindow(window);
setSizeFull();
}
}
And the following "custom-ui class"
LoginScreen.java
#UIScope
#SuppressWarnings("serial")
public class LoginScreen extends CustomComponent {
public static final String VIEW_NAME = "";
final FormLayout layout = new FormLayout();
TextField userName = new TextField();
TextField passWord = new TextField();
Button submit = new Button("Submit");
#Autowired
private TestBean testBean;
#Autowired
private String test;
public LoginScreen() {
userName.setCaption("Benutzername:");
passWord.setCaption("Passwort:");
// not working (null)
System.out.println("loginscreen test: " + testBean);
System.out.println("loginscreen test: " + test);
setSizeFull();
}
}
I'd appreciate some help...
window.setContent(new LoginScreen());
Spring should create LoginScreen if you want that #Autowired annotated fields become injected.
Just inject the LoginScreen instance in your Application class
I'm using Apache Tomcat 7.0.54 and Spring MVC 4.0.1 and trying to configure DispatcherServlet with Java:
I've written the config class:
public class AppInitializer extends AbstractDispatcherServletInitializer{
#Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/her-servlet.xml");
return context;
}
#Override
protected String[] getServletMappings() {
return new String[] {"*.her"};
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
and it doesn't work. But if I write the follwoing:
public class AppInitializer implements WebApplicationInitializer{
#Override
public void onStartup(ServletContext sc) throws ServletException {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/her-servlet.xml");
ServletRegistration.Dynamic registration = sc.addServlet("her", new DispatcherServlet(context));
registration.setLoadOnStartup(1);
registration.addMapping("*.her");
}
}
It'll work fine. I don't understand the problem. Could you help me to solve?
I cannot seem to get simple Spring application to work with JavaConfig.
public class WebApp extends AbstractAnnotationConfigDispatcherServletInitializer {
private static final Logger logger = Logger.getLogger(WebApp.class);
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ WebAppConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[]{ "/" };
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
logger.debug("onStartup");
super.onStartup(servletContext);//MUST HAVE
servletContext.setInitParameter("defaultHtmlEscape", "true");
}
#Configuration
#EnableWebMvc
#ComponentScan("com.doge.controller")
public static class WebAppConfig extends WebMvcConfigurerAdapter {
}
}
And controller:
package com.doge.controller;
#RestController
public class HelloController {
#RequestMapping("/")
public String sayHello() {
System.out.println("something");
return "index";
}
}
I always get 404 on "localhost:8080/Build" nor "localhost:8080".
Nothing is ever logged nor printed, just "INFO: Server startup in 538 ms".
There are few options of initialize Spring web application. The easiest is like below:
public class SpringAnnotationWebInitializer extends AbstractContextLoaderInitializer {
#Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext applicationContext =
new AnnotationConfigWebApplicationContext();
applicationContext.register(WebAppConfig.class);
return applicationContext;
}
}
Other options can be found here: http://www.kubrynski.com/2014/01/understanding-spring-web-initialization.html