User.java
public class User {
String id;
String name;
String password;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserDao.java
public class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3307/problem", "root", "1234");
PreparedStatement ps = c.prepareStatement("insert into users(id, name, password) values (?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException{
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3307/problem", "root", "1234");
PreparedStatement ps = c.prepareStatement("select * from users where id = ?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("Name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
}
Main.java
public class Test {
public static void main(String[] args) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
UserDao dao = new UserDao();
User user = new User();
user.setId("아이디12");
user.setName("이름");
user.setPassword("비밀번호");
dao.add(user);
System.out.println(user.getId() + " 등록 성공");
User user2 = dao.get(user.getId());
System.out.println(user2.getName());
System.out.println(user2.getPassword());
System.out.println(user2.getId() + "조회 성공");
}
}
UserDao.java
public class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("insert into users(id, name, password) values (?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException{
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement("select * from users where id = ?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("Name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
// 중복 코드의 메소드 추출 -> 관심사의 분리
public Connection getConnection() throws ClassNotFoundException, SQLException{
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3307/problem", "root", "1234");
return c;
}
}
UserDao.java
/**
* 상속을 통한 확장방법을 제공
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
Main.java
public class SubClass {
static class NUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
// N사의 DB Connection 생성 코드
return null;
}
}
static class DUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
// D사의 DB Connection 생성 코드
return null;
}
}
public static void main(String[] args) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
// UserDao dao = new DUserDao();
UserDao dao = new NUserDao();
User user = new User();
user.setId("아이디12");
user.setName("이름");
user.setPassword("비밀번호");
dao.add(user);
System.out.println(user.getId() + " 등록 성공");
User user2 = dao.get(user.getId());
System.out.println(user2.getName());
System.out.println(user2.getPassword());
System.out.println(user2.getId() + "조회 성공");
}
}
여기서 "상속으로 기능을 확장" 하는 2가지 디자인 패턴을 알려주신다.
1. 템플릿 메소드 패턴 - 슈퍼 클래스에서 어떤 기능을 실행하는 로직(템플릿 메소드)에서 변화가 필요한 부분(강제적 - 추상 메소드, 선택적 - 훅 메소드)을 알잘딱으로 구현해서 사용하도록 하는 방법
public abstract class Super {
/// 템플릿 메소드
public void templateMethod(){
hookMethod();
abstractMethod();
}
// 선택적으로 오버라이드 가능한 훅 메소드
protected void hookMethod() {}
// 서브클래스에서 반드시 구현해야되는 추상 메소드
public abstract void abstractMethod();
}
public class Sub1 extends Super{
@Override
protected void hookMethod() {
super.hookMethod();
}
@Override
public void abstractMethod() {
}
}
2. 팩토리 메소드 패턴 - 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것
UserDao.java
/**
* 상속을 통한 확장방법을 제공
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
public class SubClass {
static class NUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
// N사의 DB Connection 생성 코드
return null;
}
}
static class DUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
// D사의 DB Connection 생성 코드
return null;
}
}
> 여기서는 Connection 인터페이스를 상속 받는 클래스들이거나 인터페이스의 객체들
SimpleConnectionMaker.java
public class SimpleConnectionMaker {
public Connection makeNewConnection() throws ClassNotFoundException, SQLException{
Class.forName("com.mysql.cj.jdbc.Driver");
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3307/problem", "root", "1234");
return c;
}
}
UserDao.java
public class UserDao {
private SimpleConnectionMaker simpleConnectionMaker;
public UserDao() {
this.simpleConnectionMaker = new SimpleConnectionMaker();
}
public void add(User user) throws ... {
Connection c = simpleConnectionMaker.makeNewConnection();
...
}
public void get(String id) throws ... {
Connection c = simpleConnectionMaker.makeNewConnection();
...
}
}
ConnectionMaker.java
public interface ConnectionMaker {
public Connection makeConnection() throws ClassNotFoundException, SQLException;
}
DConnectionMaker.java (여기서 커넥션을 여기서 구현)
public class DConnectionMaker implements ConnectionMaker{
@Override
public Connection makeConnection() throws ClassNotFoundException, SQLException {
// D 사가 족자적인 방법으로 Connection 을 생성하는 코드
return null;
}
}
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao() {
// 그래도 여기는 클래스 이름이 나오네?
this.connectionMaker = new DConnectionMaker();
}
public void add(User user) throws ... {
Connection c = connectionMaker.makeConnection();
...
}
public void get(String id) throws ... {
Connection c = connectionMaker.makeConnection();
...
}
}
여기서 토비님은 클라리언트 오브젝트에 관한 이야기를 해주신다.
사용되는 오브젝트를 서비스, 사용하는 오브젝트를 클라이언트
위 코드의 생성자에서 ConnectionMaker 인터페이스 구현 클래스의 관계를 결정해주는 기능을 분리해서 두기 적당한 장소가 UserDao를 사용하는 클라이언트 오브젝트이다.
클래스 사이의 관계를 설정해주는 것이 아닌, 오브젝트와 오브젝트의 동적인 관계를 설정해줘야 된다는 게 핵심 -> 다형성을 이용하라는 말씀이시다.
ConnectionMaker.java
public interface ConnectionMaker {
public Connection makeConnection() throws ClassNotFoundException, SQLException;
}
DConnectionMaker.java
public class DConnectionMaker implements ConnectionMaker{
@Override
public Connection makeConnection() throws ClassNotFoundException, SQLException {
// D 사가 족자적인 방법으로 Connection 을 생성하는 코드
return null;
}
}
UserDao.java
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public void add(User user) throws ... {
Connection c = connectionMaker.makeConnection();
...
}
public void get(String id) throws ... {
Connection c = connectionMaker.makeConnection();
...
}
}
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
ConnectionMaker connectionMaker = new DConnectionMaker();
// ConnectionMaker connectionMaker = new NConnectionMaker();
UserDao dao = new UserDao(connectionMaker);
클래스와 모듈은 확장에는 열려있고, 변경에는 닫혀있다.
- UserDao는 DB연결 기능을 확장하는 데에는 열렸고, UserDao의 핵심코드는 그런 변화에 영향을 받지 않고 유지할 수 있다.
응집도 凝集度
凝 (엉길 응) 集 (모을 집) 度 (법도 도, 헤아릴 탁, 살 택)
- 높은 응집도
변화가 일어날때 해당 모듈에서 많은 부분이 함께 바뀐다.
응집도가 높다는 건 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되있다고 볼 수 있다.
결합도 結合度 - 하나의 오브젝트가 변할때 관계를 맺은 다른 오브젝트에게 변화를 요구하는 정도
結 (맺을 결, 상투 계) 合 (합할 합, 쪽문 합, 홉 홉) 度 (법도 도, 헤아릴 탁, 살 택)
- 낮은 결합도
관계를 맺고 있는 다른 오브젝트에게 변경에 대한 요구가 전파되지 않음을 의미 - 느슨한 연결
ConnectionMaker connectionMaker = new DConnectionMaker() --> 전략;
DaoFactory.java
public class DaoFactory {
public UserDao userDao(){
DConnectionMaker connectionMaker = new DConnectionMaker();
UserDao userDao = new UserDao(connectionMaker);
return userDao;
}
}
UserDaoTest.java
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
UserDao dao = new DaoFactory().userDao();
...
}
}
두 역할의 오브젝트를 분리함
public class DaoFactory {
public UserDao userDao(){
return new UserDao(new DConnectionMaker());
}
public AccountDao accountDao(){
return new AccountDao(new DConnectionMaker());
}
public MessageDao messageDao(){
return new MessageDao(new DConnectionMaker());
}
}
public class DaoFactory {
public UserDao userDao(){
return new UserDao(connectionMaker());
}
public AccountDao accountDao(){
return new AccountDao(connectionMaker());
}
public MessageDao messageDao(){
return new MessageDao(connectionMaker());
}
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
제어의 역전
간단히 프로그램의 제어 흐름 구조가 뒤빠뀌는 것
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao() {
// UserDao가 자신이 사용할 ConnectionMaker 구현체를 결정하는 부분
this.connectionMaker = new DConnectionMaker();
}
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = connectionMaker.makeConnection();
...
}
public User get(String id) throws ClassNotFoundException, SQLException{
Connection c = connectionMaker.makeConnection();
}
}
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = connectionMaker.makeConnection();
...
}
public User get(String id) throws ClassNotFoundException, SQLException{
Connection c = connectionMaker.makeConnection();
}
}
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
UserDao dao = new DaoFactory().userDao();
}
}
DaoFactory.java
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao(){
return new UserDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
UserDaoTest.java
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao = context.getBean("userDao", UserDao.class);
...
dao.add(user);
}
}
1) DaoFactory 클래스를 설정정보로 등록
2) @Bean이 붙은 메소드의 이름을 가져와 빈 목록을 만듬
3) 클라이언트가 애플리케이션 컨텍스트의 getBean() 메소드를 호출
4) 자신의 빈 목록에서 요청한 이름이 있는지 탐색, 있으면 빈을 생성하는 메소드를 호출
5) 오브젝트를 생성시킨 후 클라이언트에게 돌려줌
애플리케이션 컨텍스트를 사용했을 때 얻을 수 있는 장점
오브젝트의 동일성과 동등성
- 동일성 : == (메조리 주소가 같음)
- 동등성 : equals() (정보가 같음)
애플리케이션 컨텍스트는 IoC 컨테이너면서 싱글톤을 저장, 관리하는 싱글톤 레지스트리(singleton registry)다. 스프링은 default로 빈 오브젝트를 모두 싱글톤으로 생성한다.
싱글톤으로 만드는 이유
- 스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 "서버"환경.
- 수많은 요청에 따른 오브젝트의 생성은 서버의 부하를 일으킴.
- 서블릿은 멀티 스레드환경에서 싱글톤으로 동작하는 엔터프라이즈 기술의 기본이 되는 서비스 오브젝트
public class UserDao{
private static UserDao INSTANCE;
...
private UserDao(ConnectionMaker connectionMaker){
this.connectionMaker = connectionMaker;
}
public static synchronized UserDao getInstance(){
if (INSTANCE == null) INSTANCE = new UserDao(...);
return INSTANCE;
}
}
스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공 > 싱글톤 레지스트리
example
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao(){
return new UserDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
UserDao를 멀티스레드 환경에서 이렇게 사용하면 안되는 예시
public class UserDao {
// 읽기 전용
private ConnectionMaker connectionMaker;
private Connection connection; // 매번 새로운 값으로 바뀜 -> 심각한 문제 발생
private User user; // 매번 새로운 값으로 바뀜 -> 심각한 문제 발생
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public void add(User user) throws ClassNotFoundException, SQLException {
this.connection = connectionMaker.makeConnection();
...
}
public User get(String id) throws ClassNotFoundException, SQLException{
this.connection = connectionMaker.makeConnection();
this.user = new User();
this.user.setId(re.getString("id"));
...
return user;
}
}
- 읽기 전용의 정보이며, DaoFactory에서 @Bean으로 설정되어 스프링에서 한개의 오브젝트만 만들어진다.
- 스프링이 한 번 초기화해주고 나면 이후에는 수정되지 않기 때문에 멀티스레드 환경에서도 안전하다.
기존의 UserDao처럼 개별적으로 바뀌는 정보는 로컬 변수, 파라미터로 주고 받으면서 사용
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = connectionMaker.makeConnection(); // <- 이게 맞다.
...
}
public User get(String id) throws ClassNotFoundException, SQLException{
Connection c = connectionMaker.makeConnection(); // <- 이게 맞다.
PreparedStatement ps = c.prepareStatement("select * from users where id = ?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("Name"));
user.setPassword(rs.getString("password"));
return user;
}
DI 라는 용어가 생긴 이유
그래서 스프링이 제공하는 IoC 방식의 핵심을 짚어주는 "DI"라는 의도가 드러나는 용어가 탄생됨.
설계 시점에서는 몰랏던 두 오브젝트의 관계를 맺도록 도와주는 제3의 존재의 유무 -> DI의 핵심
public UserDao() {
this.connectionMaker = new DConnectionMaker;
}
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
보통 DI는 그 근간이 되는 IoC와 함께 사용해서 IoC/DI 컨테이너라는 식으로 많이 엮이는 개념이다.
private ConnectionMaker connectionMaker;
public UserDao() {
DaoFactory daoFactory = new DaoFactory();
this.connectionMaker = daoFactory.connectionMaker;
}
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao dao = context.getBean("connectionMaker", ConnectionMaker.class);
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DaoFactory.class);
this.connectionMaker = context.getBean("connectionMaker", ConnectionMaker.class);
}
...
}
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao(){
return new UserDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
...
}
DI를 원하는 오브젝트는 먼저 자기가 컨테이너가 관리하는 빈이여야 한다.
DI 받는다.
DI의 동작 방식은 외부로부터의 주입이다.
그러면 외부에서 파라미터로 오브젝트를 넘겨주면 DI인가?
- 주입 받는 메소드 파라미터가 특정 클래스 타입으로 고정되어 있다면 DI가 일어날 수 없다.
- 이건 단순 오브젝트 주입이다.- 인터페이스 타입의 파라미터여야 동적으로 구현 클래스를 제공할 수 있다.
- DI의 개념을 따르는 주입이다.
CountingConnectionMaker.java
public class CountingConnectionMaker implements ConnectionMaker{
int counter = 0;
private ConnectionMaker realConnectionMaker;
public CountingConnectionMaker(ConnectionMaker realConnectionMaker) {
this.realConnectionMaker = realConnectionMaker;
}
@Override
public Connection makeConnection() throws ClassNotFoundException, SQLException {
this.counter++; // 카운팅
return realConnectionMaker.makeConnection();
}
public int getCount(){
return this.counter;
}
}
DaoFactory.java
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao() {
return new UserDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker() {
return new CountingConnectionMaker(realConnectionMaker());
}
@Bean
public ConnectionMaker realConnectionMaker(){
return new DConnectionMaker();
}
}
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
CountingConnectionMaker dao = context.getBean("connectionMaker", CountingConnectionMaker.class);
dao.getCount(); // DB 커넥션 갯수
....
}
}
DI의 장점은 관심사의 분리를 통해 얻어지는 높은 응집도에서 나온다.
스프링은 생성자, 수정자 메소드, 초기화 메소드를 이용한 방법 외에도 다양한 의존관계 주입 방법을 지원한다.
자바 코드로 일일이 오브젝트 사이의 의존정보를 설정하는것은 번거로우니 XML로 DI 의존관계 설정 정보를 만들어보자.
- xml 문서는 미리 정해진 구조를 따라서 작성 됐는지 검사가능하다.
- xml 문서의 구조를 정의 하는 방법에는 DTD와 스키마가 있으며, 스프링의 xml 설정파일은 2가지 방법을 모두 지원한다.
- DTD보다는 스키마를 많이 쓰며 더 자세한건 검색하자.
@Configuration
public class DaoFactory {
@Bean
public ConnectionMaker connectionMaker(){
return new DConnectionMaker();
}
}
<beans>
<bean id="connectionMaker" class="패키지명.DConnectionMaker"></bean>
</beans>
<beans>
<bean id="methodName">
<bean class="a.b.c...BeanClass" >
<bean>
태그의 class attribute에 지정하는 것은 자바 메소드에서 오브젝트를 만들때 사용하는 클래스 이름이다. 메소드의 리턴 타입을 class attribute에 사용 ㄴㄴ하다.수정자 메소드가 많이 쓰였던 이유 중 하나가 XML로 의존관계 정보를 만들때 편리하는 점도 있다. (자바빈의 관례를 따라서 수정자 메소드는 프로퍼티가 된다.)
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao(){
UserDao userDao = new UserDao();
userDao.setConnectionMaker(connectionMaker());
return userDao;
}
}
<bean id="userDao" class="패키지명.UserDao">
<property name="connectionMaker" ref="connectionMaker"/>
</bean>
별 내용은 아니고 빈의 이름이 바뀌는 경우 주의사항정도의 내용이다.
<beans>
<bean id="connectionMaker" class="패키지명.DConnectionMaker"></bean>
<bean id="userDao" class="패키지명.UserDao">
<property name="connectionMaker" ref="connectionMaker"/>
</bean>
</beans>
<beans>
<bean id="myConnectionMaker" class="패키지명.DConnectionMaker"></bean>
<bean id="userDao" class="패키지명.UserDao">
<property name="connectionMaker" ref="myConnectionMaker"/>
</bean>
</beans>
applicationContext.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 id="connectionMaker" class="DConnectionMaker"></bean>
<bean id="userDao" class="UserDao">
<property name="connectionMaker" ref="connectionMaker"/>
</bean>
</beans>
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
}
}
public interface ConnectionMaker {
Connection makeConnection() throws ClassNotFoundException, SQLException;
}
UserDao.java
public class UserDao {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void add(User user) throws SQLException {
Connection = dataSource.getConnection();
...
}
...
}
DaoFactory.java
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao(){
UserDao userDao = new UserDao();
userDao.setDataSource(dataSource());
return userDao;
}
@Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(com.mysql.jdbc.Driver.class);
dataSource.setUrl("jdbc:mysql://localhost:3307/problem");
dataSource.setUsername("root");
dataSource.setPassword("1234");
return dataSource;
}
}
<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 id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
아직 DB 접속 정보가 없다.
</bean>
<bean id="userDao" class="UserDao">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
<propery>
를 이용해 주입할 정보를 지정할 때 레퍼런스인 경우는 <propery ref="">
, 단순 값인 경우는 <propery value="">
를 사용한다.<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/problem"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
url, username, password은 모두 String 타입이지만 driverClass같은 경우는 java.lang.Class 타입이다. Class 타입의 파라미터를 갖는 수정자 메소드에 어떻게 사용이 가능한걸까...
Class driverClass = Class.forName("com.mysql.cj.jdbc.Driver");
dataSource.setDriverClass(driverClass);
스프링의 관심은 "오브젝트와 그 관계" 이며, 그 오브젝트를 설계, 분리, 의존관계 결정은 개발자의 몫이다.
3줄요약