1) Spring-context : Spring IoC 컨테이너와 관련된 라이브러리
2) Spring-jdbc : Spring JDBC 관련 라이브러리
3)
new AnnotationConfigApplicationContext(AppCOnfig.class)
1) AppConfig(자바 config)객체 생성
2) 클래스나 메서드, 필드에 붙은 애노테이션 처리
Spring IoC 컨테이너 또는 Bean 컨테이너라고도 불린다.
Client에서 요청이 들어오면 DispacherServlet가 객체를 달라고 SpringIoC컨테이너에게 요청 하면 IoC는 컨테이너는 컨트롤러,서비스,DAO등의 객체를 생성후 Controller에 객체 리턴
Bean
= object 객체 = instance
IoC(Inversion of Control)
: 역제어(제어의 역전)
IoC는 DI와 Listener를 포함하는 개념
IoC컨테이너는 DI컨테이너 또는 Bean컨테이너라고도 불린다.
1) 일반적인경우 : 객체가 필요하면 생성해서 쓴다.
역제어 : 필요한 객체를 외부에서 만들어 주입해 준다.
역제어의 방식으로 프로그래밍을 하면 객체를 교체하기 쉽다. <= DI(Dependency Injection) : 의존객체 주입
2) 일반적인경우 : 어떤 작업을 수행하기 위해 메서드를 호출한다.
역제어 : 특정 상태에 놓일때 등록된 메서드가 자동호출 된다.
리스너, 필터, 서블릿 등
: 특정 상태에 놓일때 등록된 메서드가 자동호출 된다, 전형적인 역제어 방식
gradle eclipse
실행한다.// 스프링 IoC 컨테이너의 설정을 수행하는 클래스
// 1) DB 커넥션 객체 관리자 준비 : DataSource
public class AppConfig {
public AppConfig() {
System.out.println("AppConfig() 생성자 호출됨!");
}
}
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("공유 자원을 준비 중!!");
try {
// Spring IoC 컨테이너 준비
AnnotationConfigApplicationContext iocContainer =
new AnnotationConfigApplicationContext(AppConfig.class);
implementation 'org.springframework:spring-jdbc:5.3.23'
gradle eclipse
실행한다. // DataSource를 생성하는 메서드를 호출하라고 표시한다.
// 메서드가 리턴한 객체는 @Bean 애노테이션에 지정된 이름으로 컨테이너에 보관될 것이다.
@Bean
public DataSource createDataSource() {
System.out.println("createDataSource() 호출됨!");
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.mariadb.jdbc.Driver");
ds.setUrl("jdbc:mariadb://localhost:3306/studydb");
ds.setUsername("study");
ds.setPassword("1111");
return ds;
}
//객체가 리턴한 값을 transactionManager라는 이름으로 저장한다.
@Bean("transactionManager")
public PlatformTransactionManager createTransactionManager(DataSource ds) {
// Spring IoC 컨테이너는 이 메서드를 호출하기 전에
// 이 메서드가 원하는 파라미터 값인 DataSource를 먼저 생성한다.
// => createDataSource() 메서드를 먼저 호출한다.
System.out.println("createTransactionManager() 호출됨!");
return new DataSourceTransactionManager(ds);
}
// Spring IoC 컨테이너가 관리하는 개체임을 표시한다.
@Component
// - 이 애노테이션을 붙이면 Spring IoC 컨테이너가 객체를 자동 생성한다.
// - 물론 생성자의 파라미터 값을 자동으로 주입한다.
// - 파라미터에 해당하는 객체가 없다면 생성 오류가 발생한다.
public class MariaDBBoardDao implements BoardDao {
DataSource ds;
public MariaDBBoardDao(DataSource ds) {
System.out.println("4) MariaDBBoardDao() 호출됨!");
this.ds = ds;
}
// 스프링 IoC 컨테이너의 설정을 수행하는 클래스
// 1) DB 커넥션 객체 관리자 준비 : DataSource
// 2) 트랜잭션 관리자 준비 : PlaqtformTransactionManager
// 3) 어떤패키지의 있는 객체를 자동으로 생성할 것인지 지정한다.
@ComponentScan(value = "com.bitcamp.board")
// - com.bitcamp.board 패키지 및 그 하위 패키지에 소속된 클래스 중에서
// @Component, @Controller, @Service, @Repository 등의 애노테이션이 붙은 클래스를 찾아
// 객체를 생성한다.
public class AppConfig {
}
@Component
// - 이 애노테이션을 붙이면 Spring IoC 컨테이너가 객체를 자동 생성한다.
// - 객체의 이름을 명시하지 않으면
// 클래스 이름(첫 알파벳은 소문자. 예: "mariaDBBoardDao")을 사용하여 저장한다.
// - 물론 생성자의 파라미터 값을 자동으로 주입한다.
// - 파라미터에 해당하는 객체가 없다면 생성 오류가 발생한다.
public class DefaultBoardService implements BoardService {
PlatformTransactionManager txManager;
BoardDao boardDao;
public DefaultBoardService(BoardDao boardDao, PlatformTransactionManager txManager) {
System.out.println("5) DefaultBoardService() 호출됨!");
this.boardDao = boardDao;
this.txManager = txManager;
}
@Override
public void add(Board board) throws Exception {
// 트랜잭션 동작 방법을 정의한다.
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("tx1");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
@Component
// - 이 애노테이션을 붙이면 Spring IoC 컨테이너가 객체를 자동 생성한다.
// - 객체의 이름을 명시하지 않으면
// 클래스 이름(첫 알파벳은 소문자. 예: "mariaDBMemberDao")을 사용하여 저장한다.
// - 물론 생성자의 파라미터 값을 자동으로 주입한다.
// - 파라미터에 해당하는 객체가 없다면 생성 오류가 발생한다.
public class DefaultMemberService implements MemberService {
MemberDao memberDao;
public DefaultMemberService(MemberDao memberDao) {
System.out.println("5) DefaultMemberService() 호출됨!");
this.memberDao = memberDao;
};
@Component("/board/xxx")
// - 애노테이션을 붙일 때 객체 이름을 명시하면 그 이름으로 저장한다.
// - 프론트 컨트롤러는 페이지 컨트로러를 찾을 때 이 이름으로 찾을 것이다.
public class DispatcherServlet extends HttpServlet {
ApplicationContext iocContainer;
public DispatcherServlet(ApplicationContext iocContainer) {
// Spring IoC 컨테이너를 주입 받는다.
this.iocContainer = iocContainer;
}
@MultipartConfig(maxFileSize = 1024 * 1024 * 10)
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("공유 자원을 준비 중!!");
try {
// Spring IoC 컨테이너 준비
AnnotationConfigApplicationContext iocContainer =
new AnnotationConfigApplicationContext(AppConfig.class);
ServletContext ctx = sce.getServletContext();
// 자바 코드로 서블릿 객체를 직접 생성하여 서버에 등록하기
DispatcherServlet servlet = new DispatcherServlet(iocContainer);
Dynamic config = ctx.addServlet("DispatcherServlet", servlet);
config.addMapping("/service/*");
config.setMultipartConfig(
new MultipartConfigElement(this.getClass().getAnnotation(MultipartConfig.class)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class DispatcherServlet extends HttpServlet {
ApplicationContext iocContainer;
public DispatcherServlet(ApplicationContext iocContainer) {
// Spring IoC 컨테이너를 주입 받는다.
this.iocContainer = iocContainer;
}
private static final long serialVersionUID = 1L;
///java.io.Seriallizable를 구현한 애들은 seriallizable 설정해야한다 아니면 랜덤한 값으로 설정된다.
// seriallizable 객체를 seriallizable 바이트배열로 만들어서 내보낼때 사용한다.
// 프로그램을 내보낼때는 항상 버전을 정해서 보내야한다.
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
// 프론트 컨트롤럴르 경유해서 실행할 페이지 컨트롤러의 경로를 알아낸다.
// - "/service" 다음에 오는 경로, 즉 * 에 해당하는 경로를 리턴한다.
// System.out.println(pathInfo); -> /, /haha/nan/hul
String pathInfo = req.getPathInfo();
System.out.println(pathInfo);
// 페이지 컨트롤러를 찾는다.
// - Spring IoC 컨테이너는 객체를 찾지 못할 때 예외를 발생시킨다.
Controller controller = (Controller) iocContainer.getBean("pathInfo");
System.out.println("controller: " + iocContainer.getBean("pathInfo"));
// 페이지 컨트롤러를 실행한다.
resp.setContentType("text/html;charset=UTF-8");
String viewName = controller.execute(req, resp);
if (viewName.startsWith("redirect:")) { // 예) "redirect:list"
resp.sendRedirect(viewName.substring(9)); // 예) "list"
return;
} else {
req.getRequestDispatcher(viewName).include(req, resp); // JSP를 실행한 후 리턴된다.
}
} catch (Exception e) {
req.setAttribute("exception", e);
req.getRequestDispatcher("/error.jsp").forward(req, resp);
}
}
}
// 콘텐트를 틍록, 변경, 삭제하는 경우 로그인 여부를 확인한다.
if (servletPath.toLowerCase().endsWith("add") || servletPath.toLowerCase().endsWith("update")
|| servletPath.toLowerCase().endsWith("delete")) {
gradle eclipse
실행한다.// 웹애플리케이션이 시작되었을 때 공유할 자원을 준비시키거나 해제하는 일을 한다.
@MultipartConfig(maxFileSize = 1024 * 1024 * 10)
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("공유 자원을 준비 중!!");
try {
// 웹 기능이 포함된 스프 IoC 컨테이너 준비
AnnotationConfigWebApplicationContext iocContainer =
new AnnotationConfigWebApplicationContext();
iocContainer.register(AppConfig.class);
iocContainer.refresh();// 자바 config zmffotm(AppConfig)에 설정된 대로 객체를 생성한다.
ServletContext ctx = sce.getServletContext();
// 자바 코드로 서블릿 객체를 직접 생성하여 서버에 등록하기
DispatcherServlet servlet = new DispatcherServlet(iocContainer);
Dynamic config = ctx.addServlet("DispatcherServlet", servlet);
config.addMapping("/service/*");
config.setMultipartConfig(
new MultipartConfigElement(this.getClass().getAnnotation(MultipartConfig.class)));
config.setLoadOnStartup(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}