Just trying to play a bit with SOLID concepts using java.
Implementing a basic MVC framework based on a Container and Dependency Injection (automatic or defined);
There are 3 files where the application can be configured and they are all in the resources folder:
- app.json
- env.properties (gitignored)
- route.config
It's a json formatted file where the main application configuration is defined. e.g. Service Providers, Middlewares, etc...
In the app.json you can use varaibles like {{ my_var }} which are defined in the env.properties
This file is gitignored because usually it will contain sensitive data like credentials, encryptation keys and other sensitive or environment-dependent variables. Any variable declared in this file can be used in the app.json file in the format of {{ fb-app-secret }} where fb-app-secret is a key defined in env.properties
The format of every entry is http-method url-pattern controller.controller-method(params) route_name
e.x:
GET / com.mathiasgrimm.app.controller.IndexController.index()
GET /user/:id com.mathiasgrimm.app.controller.UserController.index(Integer)
Comments are allowed in any part of this file. To comment anything add a #
anywhere
The main entry point of the application is the com.mathiasgrimm.lib.servlet.MainServlet which boots the com.mathiasgrimm.lib.Application
At the moment every component defined in the container will be treated as a singleton so keep in mind that any variables defined in your classes can have a negative effect due to the threaded nature of the servlets.
You can register Services Provider in the rosource/app.json under the service-providers
object.
The provider have to implement the ServiceProviderInterface
. The providers will be registered in the same order they are
define in the config.
If your component depends one other components you can define the constructor param type with the types that are
registered in the container and it will automatically inject them for you. Remeber to add @Inject
to your constructor
public class IndexController {
private AppConfig appConfig;
private SomeConcretClass someConcretClass;
@Inject
public IndexController(AppConfig appConfig, SomeConcreteClass someConcreteClass) {
this.appConfig = appConfig;
this.someConcreteClass = someConcreteClass;
}
}
public class SomeConcreteClass {
}
if the type of your parameter is a concrete class it does not need to be registered in the container
To register a component you have to use the service providers, ex.:
public class HttpServiceProvider implements ServiceProviderInterface {
@Override
public void register(Container container) throws Exception {
container.set(MailerInterface.class, (Container ct, Class type) -> {
AppConfig appConfig = ct.get(AppConfig.class);
return new MailgunAdapter(
appConfig.get()->getString('mailgun-key'),
appConfig.get()->getString('mailgun-secret')
);
});
}
@Override
public void boot(Container container) throws Exception {
}
}
you can call (container.get
) from any other service provided and it will be loaded independently of the order they were
declared
Before any HTTP request is served, all registered component will be loaded and available
Every controller method requires the first two arguments to the HttpServletRequest
and HttpServletRespose
as these
two object cannot be defined in the controller instance due to multi-threading.
- Middleware
- ORM
- much more...