На примере Spring
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
String str = "";
while (!str.equals("exit")) {
str = scanner.nextLine();
...
@RequestMapping(path = "/")
public ModelAndView index() {
List clients = influxDAO.getDbList();
...
return new ModelAndView("clients", model, HttpStatus.OK);
}
public abstract class TestCase extends Assert implements Test {
....
protected void runTest() throws Throwable {
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
}
MovieFinder finder = (MovieFinder)
ServiceLocator.getService("MovieFinder");
Пример от Мартина Фаулера
http://www.martinfowler.com/articles/injection.html
public class MovieLister {...
public Collection<Movie> moviesDirectedBy(String director) {
List allMovies = finder.findAll();
for(Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = it.next();
if(!movie.getDirector().equals(director)) it.remove();
}
return allMovies;
}
public interface MovieFinder {
List<Movie> findAll();
}
Откуда мы возьмём конкретную реализацию?
public class MovieLister {
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
Схема зависимостей
В чём проблема?
Решение
Spring: внедрение через поле
@Component
public class ColonDelimitedMovieFinder implements MovieFinder {
}
@Component
public class MovieLister {
@Autowired
private MovieFinder finder;
}
Было/Стало
public class MovieLister {
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder("movies1.txt");
}
@Component
public class MovieLister {
@Autowired
private MovieFinder finder;
}
Spring: внедрение через конструктор
@Autowired
public class ColonDelimitedMovieFinder implements MovieFinder {
}
@Component
public class MovieLister {
private MovieFinder finder;
@Autowired
public MovieLister(MovieFinder fnd) {
this.finder = fnd;
}
...
Это объект системы, который
Spring-ом, т.е. IoC-контейнером
Может быть помечен аннотацией
@Component
public class CsvMovieFinder implements MovieFinder {
private String fileName;
...
}
Может быть создан конфигурацией
@Configuration
public class MovieFinderConfiguration {
@Bean
public MovieFinder movieFinder() {
...
Collection movies =
moviesDao.getAllMoviesFromDataBase();
...
return new CollectionMovieFinder(movies);
}
}
Например, если нужно выполнить дополнительные действия, которые не хочется делать частью логики бина
Bean может быть даже строкой
@Configuration
public class DatabaseConfiguration {
@Bean
public String databaseVendor() {
...
String vendor = getVendor();
...
return vendor;
}
}
Внедрение через поле
@Component
public class MovieLister {
@Autowired
private MovieFinder finder;
}
Внедрение через конструктор
@Component
public class MovieLister {
private MovieFinder finder;
@Autowired
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
Если внедряется один бин:
Внедрение списка бинов
@Component
public class MartinScorsese implements Director {
@Component
public class JamesCameron implements Director {
@Component
public class DirectorsService {
@Autowired
private List<Director> allDirectors;
Если есть несколько реализаций одного интерфейса
Внедрение бина по имени
@Component("csvFinder")
public class CsvMovieFinder implements MovieFinder {
@Component("oracleFinder")
public class OracleMovieFinder implements MovieFinder {
@Component
public class MovieLister {
@Autowired @Qualifier("csvFinder")
private MovieFinder finder;
Если есть несколько реализаций одного интерфейса
Получение бина из фабрики
@Component
public class MovieLister {...
@Autowired
private BeanFactory factory;
private String beanName;
public Collection moviesDirectedBy(String director) {
MovieFinder finder = factory.getBean(beanName);
List allMovies = finder.findAll();
@PostConstruct
@PostConstruct
@Component
public class CachingMovieLister {
@PostConstruct
public void populateMovieCache() {
// Загружаем данные из БД в кэш
cache.addAll(readFromDataBase());
}
}
@PreDestroy
Бин удаляется из фабрики
@PreDestroy
Зависит от Scope
@Component
public class CachingMovieLister {
@PreDestroy
public void clearMovieCache() {
// Освобождаем кэш
cache.clear();
}
}
@Configuration
public class MovieFinderConfiguration {
@Bean
@Scope("prototype")
public CsvMovieFinder csvMovieFinder() {
return new CsvMovieFinder("movies.csv");
}
}
@Component
public class SomeBean {
@Value("#{systemProperties['influxHost']}")
private String influxHost;
}
Системное свойство можно задать через
Аналог: System.getProperty("influxHost")
@Component
public class InfluxDAO {
public InfluxDAO(
@Value("${influx.host}") String influxHost...
}
Конфигурация задаётся в property файлах
Внимание! $ вместо #
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
Controller - это тоже Component, т.е. Bean
@Documented
@Controller
@ResponseBody
public @interface RestController {
RestController - это тоже Controller, т.е. Component...
@Controller
public class HistoryController {
@RequestMapping(path = "/history/{client}")
public ModelAndView indexLast864(
@PathVariable("client") String client,
@RequestParam(name = "count") int count)
...
Map model = new HashMap<>(d.asModel());
model.put("client", client);
return new ModelAndView("history", model, HttpStatus.OK);
}
...
<div class="container">
<br>
<h1>Performance data for "${client}"</h1>
<h3>
<a class="btn btn-success btn-lg" href="/">Client list</a>
</h3>
<h4 id="date_range"></h4>
${client} - подстановка значения из модели
@Controller
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String printHello(ModelMap model) {
model.addAttribute("message", "Hello Spring MVC Framework!");
return "hello";
}
}