IoC - DI(의존성 주입)
주입의 방법 3가지
- Field injection (파라미터)
- Setter injection (세터)
- Constructor injection (생성자)
Spring에서는 setter와 생성자를 이용한 DI 를 이용한다.
모듈 정의, 다형성을 이용한 인터페이스 화
public interface Module {
public void func1();
}
-----------------
public class Module1 implements Module{
public void func1() {
System.out.println("Module1 run...");
}
}
-----------------
public class Module2 implements Module{
public void func1() {
System.out.println("Module2 run...");
}
}
Setter를 이용한 주입
public class ModuleService {
Module module;
public void setModule(Module module) {
this.module = module;
}
--------- App
public class App {
public static void main(String[] args) {
ModuleService moduleService = new ModuleServic
moduleService.setModule(new Module1());
moduleService.work(); // module run1...
}
}
생성자를 통한 주입
public class ModuleService {
Module module;
ModuleService(Module module){
this.module = module;
}
}
--------- App
public class App {
public static void main(String[] args) {
ModuleService moduleService = new ModuleService(new Module1());
moduleService.work(); // module run1...
}
}
Spring 2.X 에선 XML에서 객체를 생성하고 이를 주입하는 형태로 구성을 하였다.
web.xml - DispatcherSevlet을 이용한 매핑, applicationContext.xml 세팅
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<welcome-file-list>
<welcome-file>index.do</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>sts03</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet/servlet-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>sts03</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-------- applicationContext.xml
<bean id="module" class="com.bit.spring.non.module.Module2"></bean> // Module2 객체 생성
<bean id="ms" class="com.bit.spring.non.service.ModuleService">
<property name="module" ref="module"></property>
<constructor-arg ref="module"></constructor-arg> // 생성자가 반드시 있어야함
</bean>
-------- App
public class App {
public static void main(String[] args) {
ApplicationContext ac = null;
ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
ModuleService my = (ModuleService) ac.getBean("ms"); // 생성자를 통한 주입
my.work(); // Module2 run...
}
}
XML에서 각 타입에 맞게 주입 가능
기본 타입
---------- applicationContext.xml
<bean id="nal" class="java.util.Date"></bean>
<bean id="module" class="com.bit.spring.service.Module3">
<property name="boo" value="true"></property>
<property name="ch1" value="@"></property>
<property name="su1" value="1234"></property>
<property name="su2" value="123456789"></property>
<property name="su3" value="3.14"></property>
<property name="msg" value="abcdefg"></property>
<property name="nalja" ref="nal"></property>
</bean>
---------- Module
import java.util.Date;
public class Module3 {
boolean boo;
char ch1;
int su1;
long su2;
double su3;
String msg;
Date nalja;
public void setBoo(boolean boo) {
this.boo = boo;
}
public void setCh1(char ch1) {
this.ch1 = ch1;
}
public void setSu1(int su1) {
this.su1 = su1;
}
public void setSu2(long su2) {
this.su2 = su2;
}
public void setSu3(double su3) {
this.su3 = su3;
}
public void setMsg(String msg) {
this.msg = msg;
}
public void setNalja(Date nalja) {
this.nalja = nalja;
}
public void func() {
System.out.println(boo);
System.out.println(ch1);
System.out.println(su1);
System.out.println(su2);
System.out.println(su3);
System.out.println(msg);
System.out.println(nalja);
}
}
배열
----------- applicationContext.xml
<bean id="module" class="com.bit.spring.service.Module4">
<property name="msgs">
<array>
<value>item1</value>
<value>item2</value>
<value>item3</value>
<value>item4</value>
<value>item5</value>
</array>
</property>
</bean>
----------- Module
public class Module4 {
String[] msgs;
public void setMsgs(String[] msgs) {
this.msgs = msgs;
}
public void func() {
for(String msg : msgs) {
System.out.println(msg);
}
}
}
List
----------- applicationContext.xml
<bean id="set" class="java.util.HashSet"></bean>
<bean id="module" class="com.bit.spring.service.Module5">
<property name="list" ref="set"></property>
</bean>
----------- Module
public class Module5 implements Module {
Set<String> list;
public void setList(Set<String> list) {
this.list = list;
}
public void func() {
for(String msg : list) {
System.out.println(msg);
}
}
}
Map
----------- applicationContext.xml
<bean id="module" class="com.bit.spring.service.Module6">
<property name="map">
<props>
<prop key="key1">val1</prop>
<prop key="key2">val2</prop>
<prop key="key3">val3</prop>
<prop key="key4">val4</prop>
</props>
</property>
<property name="map">
<map>
<entry key="key1">
<value>val1</value>
</entry>
<entry key="key2">
<value>val2</value>
</entry>
<entry key="key3">
<value>val3</value>
</entry>
</map>
</property>
</bean>
----------- Module
public class Module6 implements Module {
Map<String,String> map ;
Properties props;
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setPros(Properties props) {
this.props = props;
}
public void func() {
Set<Entry<String,String>>entrys = map.entrySet();
for(Entry<String,String> entry : entrys) {
System.out.println("key :" +entry.getKey()+", val : "+ entry.getValue());
}
}
}
AOP (Aspect Oriented Programming) 관점지향프로그래밍
이전, 이후와 같이 현재의 메서드의 진행 기준을 잡고 이 기준으로 관점을 나누고 관점에 따라 모듈을 만드는 프로그래밍
현재의 Spring에서는 직접 만들어 사용하는 경우는 거의 없으나 트랜잭션에서 사용되어지고 있음
applicationContext.xml
<bean id="myService" class="com.bit.spring.aop.CoreService">
<property name="msg" value="abcde"></property>
<property name="name" value="user1"></property>
<property name="su" value="0"></property>
</bean>
<bean id="methodBeforeAdvice" class="com.bit.spring.aop.BeforePrint"></bean>
<bean id="afterReturningAdvice" class ="com.bit.spring.aop.AfterPrint"></bean>
<bean id="throwsAdvice" class="com.bit.spring.aop.AfterErr"></bean>
<bean id="methodInterceptor" class="com.bit.spring.aop.AroundPrint"></bean>
<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns" >
<array>
<value>.*All.*</value>
<value>.*One.*</value>
</array>
</property>
</bean>
<bean id="beforePointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointcut"></property>
<property name="advice" ref="methodBeforeAdvice"></property>
</bean>
<bean id="afterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointcut"></property>
<property name="advice" ref="afterReturningAdvice"></property>
</bean>
<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<array>
<value>deptDao</value>
</array>
</property>
<property name="interceptorNames">
<list>
<value>beforePointcutAdvisor</value>
<value>afterPointcutAdvisor</value>
</list>
</property>
</bean>
CoreService
public class CoreService {
String msg;
String name;
int su;
public void setMsg(String msg) {
this.msg = msg;
}
public void setName(String name) {
this.name = name;
}
public void setSu(int su) {
this.su = su;
}
public String getMsg() {
return msg;
}
public String printHelloMsg(String msg2) {
String result = name + "님 "+msg2;
System.out.println(msg2);
return result;
}
public void printMsg() {
System.out.println(msg);
}
public void printName() {
System.out.println(name);
}
public void printDiv() throws Exception {
// double result = msg.toCharArray()[su];
// System.out.println(result);
if(su==0) throw new Exception("내가 던진 오류");
}
}
aop 클래스들
-------------------- BeforePrint (이전 실행)
public class BeforePrint implements MethodBeforeAdvice {
Logger log = Logger.getLogger(this.getClass());
public void before(Method method, Object[] args, Object target) throws Throwable {
log.debug(method.getName()+":"+Arrays.toString(args));
// System.out.println("<<<<<<<<<<");
// System.out.println(method.getName());
// System.out.println(method);
// System.out.println(Arrays.toString(args));
// System.out.println(target);
// System.out.println("before : " +((CoreService)target).getMsg());
}
}
------------------- AfterPrint (이후 실행)
public class AfterPrint implements AfterReturningAdvice {
Logger log = Logger.getLogger(this.getClass());
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
// System.out.println(">>>>>>>>>>" + returnValue);
log.debug(returnValue);
}
}
------------------ AroundPrint (이전 또는 이후 커스텀)
public class AroundPrint implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object obj = null;
try {
obj = invocation.proceed();
System.out.println("after returning");
} catch (Exception e) {
System.out.println("after throw");
}
return obj;
}
}
----------------- AfterErr (에러 발생 후)
public class AfterErr implements ThrowsAdvice {
public void afterThrowing(Exception ex) {
System.out.println("에러발생...");
System.out.println(ex);
}
}
CRUD 예제
applicationContext.xml
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="classpath:/db.properties"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="${db.mysql.url}"/>
<property name="username" value="${db.mysql.username}"/>
<property name="password" value="${db.mysql.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="deptDao" class="com.bit.spring.model.DeptDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
db.properties
db.mysql.url=jdbc:mysql://localhost:3306/lecture
db.mysql.username=scott
db.mysql.password=tiger
DeptDao (interface)
public interface DeptDao {
List<DeptVo> findAll();
DeptVo findOne(int rownum);
void insertOne(DeptVo bean);
int updateOne(DeptVo bean);
int deleteOne(int rownum);
}
DeptDaoImpl
public class DeptDaoImpl extends JdbcDaoSupport implements DeptDao{
public List<DeptVo> findAll() {
String sql = "select * from dept";
return getJdbcTemplate().query(sql, new RowMapper<DeptVo>() {
public DeptVo mapRow(ResultSet rs, int rowNum) throws SQLException {
return new DeptVo(rs.getInt("deptno"), rs.getString("dname"), rs.getString("loc"));
}
});
}
public DeptVo findOne(int rownum) {
String sql = "select * from dept where deptno=?";
return getJdbcTemplate().queryForObject(sql, new RowMapper<DeptVo>() {
public DeptVo mapRow(ResultSet rs, int rowNum) throws SQLException {
return new DeptVo(rs.getInt("deptno"), rs.getString("dname"), rs.getString("loc"));
}
}, rownum);
}
public void insertOne(DeptVo bean) {
String sql = "insert into dept value (?,?,?)";
getJdbcTemplate().update(sql, bean.getDeptno(), bean.getDname(), bean.getLoc());
}
public int updateOne(DeptVo bean) {
String sql = "update dept set dname=?, loc=? where deptno=?";
return getJdbcTemplate().update(sql, bean.getDname(), bean.getLoc(), bean.getDeptno());
}
public int deleteOne(int rownum) {
String sql = "delete from dept where deptno=?";
return getJdbcTemplate().update(sql, rownum);
}
}
Controller
------------------ ListController
public class ListController implements Controller {
DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView();
mav.setViewName("dept/list");
mav.addObject("list", deptDao.findAll());
return mav;
}
}
------------------ AddController
public class AddController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView();
mav.setViewName("dept/add");
return mav;
}
}
------------------ DetailController
public class DetailController implements Controller {
DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
int deptno = Integer.parseInt(request.getParameter("deptno"));
ModelAndView mav = new ModelAndView("dept/detail", "bean", deptDao.findOne(deptno));
return mav;
}
}
------------------ UpdateController
public class UpdateController extends AbstractCommandController{
DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
@Override
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command,
BindException errors) throws Exception {
DeptVo bean = (DeptVo) command;
deptDao.updateOne(bean);
return new ModelAndView("redirect:list.do");
}
}
------------------ DeleteController
public class DeleteController implements Controller {
DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
int deptno = Integer.parseInt(request.getParameter("deptno"));
deptDao.deleteOne(deptno);
return new ModelAndView("redirect:list.do");
}
}
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>
<!-- Handler Mapping -->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<props>
<prop key="/index.do">index</prop>
<prop key="/dept/list.do">list</prop>
<prop key="/dept/add.do">add</prop>
<prop key="/dept/insert.do">insert</prop>
<prop key="/dept/detail.do">detail</prop>
<prop key="/dept/update.do">update</prop>
<prop key="/dept/delete.do">delete</prop>
</props>
</property>
</bean>
<bean id="index" class="com.bit.sts02.controller.IndexController"></bean>
<bean id="list" class="com.bit.sts02.controller.ListController">
<property name="deptDao" ref="deptDao"></property>
</bean>
<bean id="add" class="com.bit.sts02.controller.AddController"></bean>
<bean id="insert" class="com.bit.sts02.controller.InsertController">
<property name="supportedMethods" value="POST"></property>
<property name="commandName" value="bean"></property>
<property name="commandClass" value="com.bit.spring.model.DeptVo"></property>
<property name="deptDao" ref="deptDao"></property>
</bean>
<bean id="detail" class="com.bit.sts02.controller.DetailController">
<property name="deptDao" ref="deptDao"></property>
</bean>
<bean id="update" class="com.bit.sts02.controller.UpdateController">
<property name="supportedMethods" value="POST"></property>
<property name="commandName" value="bean"></property>
<property name="commandClass" value="com.bit.spring.model.DeptVo"></property>
<property name="deptDao" ref="deptDao"></property>
</bean>
<bean id="delete" class="com.bit.sts02.controller.DeleteController">
<property name="deptDao" ref="deptDao"></property>
</bean>
<!-- View Resolve -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
junit
DaoDeptTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DeptDaoTest {
static ApplicationContext ac;
private DeptDao deptDao;
private DeptVo target;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
}
@Before
public void setUp() throws Exception {
deptDao = (DeptDao) ac.getBean("deptDao");
target = new DeptVo(99, "test", "test");
}
@Test
public void testDataSource() throws SQLException {
DataSource dataSource =(DataSource) ac.getBean("dataSource");
Connection conn = dataSource.getConnection();
assertNotNull(conn);
conn.close();
}
@Test
public void testJdbcTemplate() {
JdbcTemplate jdbcTemplate =(JdbcTemplate) ac.getBean("jdbcTemplate");
assertNotNull(jdbcTemplate);
}
@Test
public void test1FindAll() {
List<DeptVo> list = deptDao.findAll();
assertNotNull(list);
assertSame(6, list.size());
}
@Test
public void test2InsertOne() {
deptDao.insertOne(target);
assertFalse(false);
}
@Test
public void test3FindOne() {
DeptVo bean = deptDao.findOne(target.getDeptno());
assertEquals(target, bean);
}
@Test
public void test4UpdateOne() {
target.setDname("테스트");
assertSame(1, deptDao.updateOne(target));
}
@Test
public void test5DeleteOne() {
assertSame(1, deptDao.deleteOne(target.getDeptno()));
}
@AfterClass
public static void tearDownAfterClass() throws Exception {}
@After
public void tearDown() throws Exception {}
}
'회고록(TIL&WIL)' 카테고리의 다른 글
TIL 2023.03.06 Spring Framework 3.X (annotation, ibatis) (0) | 2023.03.06 |
---|---|
TIL 2023.03.03 docker tomcat 배포 (0) | 2023.03.06 |
TIL 2023.02.27 Spring framework ver 2.X (0) | 2023.02.27 |
TIL 2023.02.23 Java Web 12 (Struts frame work example, (feat.MongoDB)) (0) | 2023.02.24 |
TIL 2023.02.22 Java Web 11 (JdbcTemplate, MongoDB replica set) (0) | 2023.02.22 |