ํ ๋น์ ์คํ๋ง#1 ์ค๋ธ์ ํธ์ ์์กด๊ด๊ณ
by JiwonDev# ์คํ๋ง์ด๋ ๋ฌด์์ธ๊ฐ?
2004๋ ์ ๋ฑ์ฅํ ์๋ฐ ์ํฐํ๋ผ์ด์ฆ ์ฑ ๊ฐ๋ฐ์ ์ฌ์ฉ๋๋ ํ๋ ์์ํฌ. ์คํ๋ง์ ๋จ์ํ ํ ํ์ฌ๊ฐ ๋์ ๋ฒ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๋๊ตฌ๊ฐ ์๋๋ค. ์ค๋์ ๋ถํฐ ์๋ฐ ์ํฐํ๋ผ์ด์ฆ ์์คํ ์ ๊ฐ๋ฐํด์ค๊ณ ์ฐ๊ตฌํด์จ ์ ๋ง์ ์ฌ๋๋ค์ ๊ฒฝํ์ด ์ง์ฝ๋ ๊ฒฐ์ ์ฒด์ด๋ค. ์์ํ ์๋ฐ ์ฝ๋(POJO, Plain Old Java Object)๋ฅผ ์ถ๊ตฌํ ๋จ์ํจ๊ณผ ๊ฒฐํฉ๋์ ์์กด์ฑ์ ๋ฎ์ถฐ ์๋น์ค๋ฅผ ์ถ์ํํ๊ณ , ์๋ง์ ๋๊ตฌ๋ค๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์๋ ์ ์ฐ์ฑ์ ์ ๊ณตํ๋ค.
- ์ฑ์ ๊ธฐ๋ณธ ํ ์ ๊ณต - ์คํ๋ง ์ปจํ
์ด๋
์ปจํ ์ด๋ ๋๋ ์ฑ ์ปจํ ์คํธ๋ผ๊ณ ๋ถ๋ฆฌ๋ ๋ฐํ์ ์์ง์ ์ ๊ณตํ๋ค. ์คํ๋ง์ ๊ฐ๋ฐ์์ ์ค์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์๋ธ๋ฆฟ์ด๋ ์๋น์ค ๊ฐ์ฒด๋ฅผ ์ปจํ ์ด๋์ ๋ฑ๋กํด์ ์ฌ์ฉํ๋ค. (๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ ์ ์์ง๋ง ๋ณดํต ์น ๋ชจ๋์ ์ฌ์ฉํ๋ค.) - ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ ํ๋ ์์ํฌํ
์คํ๋ง์ ์ธ๊ฐ์ง ํต์ฌ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ์ ์ง์ํ๋ค.
1. IoC/DI๋ผ ๋ถ๋ฆฌ๋ ์ค๋ธ์ ํธ์ ์๋ช ์ฃผ๊ธฐ์ ์์กด๊ด๊ณ ๋ชจ๋ธ
2. ์๋น์ค์ ์ถ์ํ. ํน์ ์๋ฒ, ๊ธฐ์ ์ ์ข ์๋์ง ์๊ณ ์ด์์ฑ์ด ๋ฐ์ด๋ ์ฑ์ ๋ง๋ฌ.
3. AOP. cross-cutting cocern์ ๋ชจ๋๋ก ๋ ๋ฆฝํํ๋ ๊ธฐ์ - ๊ธฐ์ API
ํ์ ์์ ์ฌ์ฉํ๋ ๊ฑฐ์ ๋ชจ๋ ๊ธฐ์ ์ ๋ํด API์ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ค. https://spring.io/
# ์ค๋ธ์ ํธ์ ์์กด๊ด๊ณ
@ ๊ธฐ์กด์ ๋ฐฉ์
์คํ๋ง์ ์๋ฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ๊ธฐ์ ์ด๋ค. ์๋ฐ์ ์คํ๋ง ๋ ๋ค ๊ฐ์ฅ ์ค์ํ๊ฒ ๊ฐ์น๋ฅผ ๋๋ ๊ฒ์ ๋ฐ๋ก '๊ฐ์ฒด'์ด๋ค. ์ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ์ ๋ณด๋ฅผ JDBC API๋ฅผ ์ด์ฉํ DAO(Data Access Object, DB๋ฅผ ๋ด๋นํ๋ ๊ฐ์ฒด)๋ฅผ ๋ง๋ค์ด๋ณด์.
// User ๊ฐ์ฒด. ์ด์ UserDAO๋ฅผ ๋ง๋ค์ด๋ณด์
@Getter @Setter
public class User {
String id;
String name;
String password;
}
์ด ๊ฐ์ฒด๋ฅผ DB ํ ์ด๋ธ๋ก ๊ตฌ์ฑํ๋ฉด ์๋์ ๊ฐ์ ๊ฒ์ด๋ค.
ํ๋๋ช | ํ์ | ์ค์ |
Id | VARCHAR(10) | PK ( Primary Key ) |
Name | VARCHAR(20) | NN ( Not Null ) |
Password | VARCHAR(20) | NN |
์ด๋ฅผ MySQL๋ฑ์ ์ฌ์ฉํด์ ๊ตฌํํ๋ค๋ฉด ์๋์ ๊ฐ์ CREATE TABLE ๋ช ๋ น์ ์คํํ๋ฉด ๋๋ค.
create table users{
id varchar(10) primary key,
name varchar(20) not null,
password varchar(10) not null
}
์ ์ด์ ์ด ๋๊ฐ๋ฅผ JDBC API๋ฅผ ์ด์ฉํด ์ฌ์ฉ์ ์ ๋ณด๋ฅผ DB์ ์ ์ฅํ๋ UserDao ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด์.
- DB ์ฐ๊ฒฐ์ ์ํ JDBC Connection์ ๊ฐ์ ธ์จ๋ค
- SQL์ ๋ด์ Statement ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
- ๋ง๋ค์ด์ง Statement ๊ฐ์ฒด๋ฅผ ์คํํ๋ค
- ์กฐํ์ ๊ฒฝ์ฐ SQL ์คํ ๊ฒฐ๊ณผ๋ฅผ ResultSet์ ๋ฐ์ ๊ฐ์ฒด์ ์ฎ๊ฒจ์ค๋ค.
- ์์ ์ค์ ์์ฑ๋ ๋ฆฌ์์ค๋ ์์ ์ ๋ง์นํ ๋ฐ๋์ ๋ฐํํด์ผํ๋ค.
- JDBC API๊ฐ ๋ง๋ค์ด๋ด๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ๋ค. ๋จ ์์ธ๊ฐ ๋ฐ์ํ ์์ ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํด์ฃผ์ด์ผํ๋ค.
public class UserDao {
// ์์ธ์ฒ๋ฆฌ๋ ์์ ์์๋ ํ์ง์์๋ค. ํ์ง๋ง ์ค์ ์ฝ๋์์๋ ์ํฉ์ ๋ฐ๋ผ ๋ค ์ฒ๋ฆฌํด์ฃผ์ด์ผํ๋ค.
public void add(User user) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/myDB", "id", "password");
String query = "insert into users(id, name, password) value(?,?,?)";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, user.getId()); // ๋ณ์ ์ง์
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate(); // ์ฟผ๋ฆฌ ์คํ
ps.close();
conn.close();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/myDB", "id", "password");
String query = "select * from users where id = ?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
User user = new User();
rs.next(); // ์ฌ๋ฌ ๊ฐ์ผ ๊ฒฝ์ฐ while(rs.next());
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
conn.close();
return user;
}
}
์ ๋ฒ ๋ณต์กํด ๋ณด์ด๋ ์ฝ๋๊ฐ ๋ง๋ค์ด์ก๋ค. ์ด ์ฝ๋๊ฐ ์ ๋๋ก ๋์ํ๋์ง ํ์ธํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
- ์น ์ฑ์ ์ค์ ์๋ฒ์ ๋์ DB ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ ค๋ณธ๋ค => ํ ์คํธ์น๊ณ ๋ ๋น์ฉ์ด ๋๋ฌด ํฐ๋ฐ?
- ์๋ํ ๊ฒ์ด๋ผ ๋ฏฟ๊ณ ๊ธฐ๋ํ๋ค. => ์ง์ฌ์ผ๋ก?
- main ๋ฉ์๋์ DAO๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฝ์์ฐฝ์ ์ฐ์ด๋ณธ๋ค.
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDao dao = new UserDao();
User user = new User();
user.setPassword("pw");
user.setName("name");
user.setId("id");
dao.add(user);
// ์! ์ ๋์ํ๋ ๊ตฌ๋ง!
System.out.println("[insert ์ฑ๊ณต] user = " + user.getId());
}
์ด ๋ฐฉ๋ฒ์๋ ์ ๋ง, ์ ๋ง ๋ง์ ๋ฌธ์ ๋ค์ด ์จ์ด์๋ค. ๋ง์ฝ ์ค์ ๊ฐ๋ฐ์๊ฐ ์ด๋ฌํ ์ฝ๋๋ฅผ ์์ฑํ๋ค๋ฉด ๊ฐ๋ฐํ์ ์๋ฐ๋ก ์ซ๊ฒจ๋์ง ์์๊น ์ถ๋ค. ์ด๋ฅผ ๊ฐ์ฒด์งํฅ์ ์ธ ์ฝ๋๋ก ๊ฐ์ ํด๋๊ฐ๋ฉฐ, ์คํ๋ง์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ๋ฌด์์ธ์ง ์์๋ณด์.
- ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ๋ก์ง์ ์คํํ๊ณ , ๊ฐ์ฒด๋ฅผ ํ์ํ๋ ๋ฑ ๋๋ฌด ๋ง์ ์ฑ ์์ ํ ๊ฐ์ฒด๊ฐ ์ง๋๊ณ ์๋ค.
- main ์ค๋ ๋ ํ๋๋ก ๋ชจ๋ ํ ์คํธ๋ฅผ ๊ด๋ฆฌํ๊ณ ์๋ค.
- ์ฝ๋๋ฅผ ๊ฐ๋จํ๊ฒ ์์ ํด๋ ์ฑ ์ ์ฒด์ ์ํฅ์ ๋ฏธ์น ์ ์๋ค.
- ๋ก๊ทธ๋ฅผ ์ฝ์์ ์ฐ๊ณ ์๋ค. ๋น์ฉ์ด ํฌ๊ณ Thread-Safetyํ์ง ์๋ค.
- ์ผ๋ถ๋ถ๋ง ์ชผ๊ฐ์ ๋จ์๋ก ํ ์คํธํ ์ ์๋ค.
@ ๊ฐ์ 1. ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ(Separation of Concerns)
UserDao์์๋ [DB์ปค๋ฅ์ ์ ๋ง๋ค๊ณ , ํ์ํ๋ ์ค์ ๋ถ๋ถ]๊ณผ ์ง์ [User ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์คํ๋ถ๋ถ]์ด ํ๋๋ก ํฉ์ณ์ ธ์๋ค. ์ด ๋ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌ์ํค๊ณ ๋ชจ๋ํํ์ฌ ๋ฐ๋ณต๋๋ ์ฝ๋๋ฅผ ์ค์ฌ๋ณด์.
- ๊ด์ฌ์ฌ1. DB ์ฐ๊ฒฐ์ ํ๊ธฐ ์ํ ์ปค๋ฅ์
- ๊ด์ฌ์ฌ2. ์ฌ์ฉ์ ๋ฑ๋ก์ ์ํ SQL ๋ฌธ์ฅ (Statement ๊ฐ์ฒด)๋ฅผ ๋ง๋ค๊ณ ์คํํ๊ธฐ
- ๊ด์ฌ์ฌ3. ์์ ์ด ๋๋๊ณ ๋ ํ DB ์ปค๋ฅ์ ์์์ ํ์
์ด๋ ๊ฒ ์ ์๋๋ก ๋ฐ๋ณต๋๋ ์ค์ ๋ถ๋ถ์ Cross-Cutting Corcern (๋๋ ๊ณตํต๊ด์ฌ์ฌํญ)์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/myDB", "id", "password");
return conn;
}
public User get(String id) throws SQLException, ClassNotFoundException {
Connection c = getConnection();
// ์ดํ ์ฝ๋ ์๋ต
}
์ฌ๊ธฐ์ ํ๊ฑธ์ ๋ ๋์๊ฐ ์ฌ์ ์ด ์ปค์ง๋ฉด์ N์ฌ์ D์ฌ์ ์ฌ์ฉ์๊ด๋ฆฌ๋ฅผ ๋์์ ๋งก๊ฒ ๋์๋ค๊ณ ์์ํด๋ณด์. ์ด์ UserDao๋ ๊ฐ ํ์ฌ๋ง๋ค ๋ค๋ฅธ DB๋ฅผ ํตํฉํด์ ์ฌ์ฉํด์ผํ๋ค. ์ด๋ป๊ฒ ํ์ฅํ ์ ์์๊น?
public abstract class UserDao{
...
// ์ถ์ํด๋์ค๋ก ๋ง๋ค์๋ค.
public abstract Connection getConnection() throws ClassNotFoundException, SQLException;
}
public class DUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("N์ฌ์ DB ์ปค๋ฅ์
์์ฑ");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/myDB", "id", "password");
return conn;
}
}
public class NUserDao extends UserDao {
@Override
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName("D์ฌ์ DB ์ปค๋ฅ์
์์ฑ");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/myDB", "id", "password");
return conn;
}
}
์ฐธ๊ณ ๋ก ์ด๋ฐ ํํ๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ํ ํ๋ฆฟ ๋ฉ์๋, ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
UserDao์ ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ์ ์ฉํด์ getConnection()์ ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ๋๊ฒ ์ข์ ๊ฒ ๊ฐ์์
- ํ
ํ๋ฆฟ ๋ฉ์๋ ํจํด (Template method pattern)
๋ถ๋ชจ์์ ๊ธฐ๋ณธ์ ์ธ ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ , ์ธ๋ถ์ ์ธ ๋ฉ์๋๋ฅผ ์ถ์๋ฉ์๋๋ก ๋ฌ ์์์ด ๊ตฌํํด ์ฌ์ฉํ๋ ๋ฐฉ์
๋ชจ๋ ๊ฐ์ฒด๊ฐ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉํ๋ ๋์์ ๋ถ๋ชจ(ํ ํ๋ฆฟ)๋ฅผ ํตํด ์ถ์ํ(์ธํฐํ์ด์ค ํ) ์ํค๋ ๊ฒ.
- ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด (Factory method pattern)
๊ฐ์ฒด ์์ฑ ๋ฐฉ๋ฒ(ํฉํ ๋ฆฌ ํด๋์ค์ ์ญํ )์ ์๋ธํด๋์ค์ ์์ํ์ฌ ์บก์ํ ํ๋ ๊ฒ (์ํผํด๋์ค๋ ๊ด์ฌ X)
์ฐธ๊ณ ๋ก ์๋ฐ์์๋ ์ค๋ธ์ ํธ๋ฅผ ์์ฑ(new)ํ๋ ๊ฐ์ฒด๋ ๋ฉ์๋๋ฅผ 'ํฉํ ๋ฆฌ ๊ฐ์ฒด or ๋ฉ์๋'๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ๊ตฌํํ ๋ ์ฃผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ผ ์ด๋ฐ ์ด๋ฆ์ด ๋ถ์ ๊ฒ. [ํฉํ ๋ฆฌ ๋ฉ์๋ == ํจํด] ์๋!
// ํฉํ ๋ฆฌ ๋ฉ์๋ ํจํด์ ์ฌ์ฉ์์
// ๊ตฌ์ฒด์ ์ธ ์์ฑ๋ฐฉ๋ฒ์ ์๋ธํด๋์ค์ ์บก์ํํ๋ค. (๋ถ๋ชจ๋ ๊ด์ฌX)
Factory factory = new IDCardFactory();
Product card1 = factory.create("ํ๊ธธ๋"); // factory ์ธํฐํ์ด์ค๋ก Product์ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ ๋ค.
Product card2 = factory.create("์ด์์ "); // ๊ตฌ์ฒด์ ์ธ ์์ฑ๋ฐฉ๋ฒ์ factory์ ์๋ธํด๋์ค๊ฐ ๋ด๋น.
Product card3 = factory.create("๊ฐ๊ฐ์ฐฌ"); // Product card3 = new IDProduct("id")
card1.use();
card2.use();
card3.use();
abstract class Factory {
public final Product create(String owner) {
Product p = createProduct(owner); // ๊ฐ์ฒด์์ฑ ๋ฐฉ๋ฒ์ ์๋ธํด๋์ค๊ฐ ๊ฒฐ์
registerProduct(p);
return p;
}
protected abstract Product createProduct(String owner);
protected abstract void registerProduct(Product p);
}
class IDCardFactory extends Factory {
@Override
protected Product createProduct(String owner) { return new IDCard(owner); }
// .. ์ดํ ๊ตฌํ๋ถ ์๋ต
}
class AdminCardFactory extends Factory {
@Override
protected Product createProduct(String owner) { return new IDCard(owner); }
// .. ์ดํ ๊ตฌํ๋ถ ์๋ต
}
@๊ฐ์ 2 ๋ฌด์ง๋ ์ฐ๋ฆฌ์ ๋ฌด๊ธฐ. ์ธํฐํ์ด์ค๋ฅผ ํตํ ๋ถ๋ฆฌ
๊ฐ์ฒด๊ฐ ์๋ก๋ฅผ ๋ชฐ๋ผ๋ ์ฌ์ฉํ ์ ์๊ฒ ๋ถ๋ฆฌ์์ผ ๋ฒ๋ฆฌ์. ์ฆ ํ ๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ์ ๋ ๋ณ๊ฒฝ์ด ํ์ฐํ๋ ๊ฒ์ ๋ง์.
๋ค๋ง ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด๋ ๊ฒฐ๊ตญ ์ธ์ ๊ฐ๋ '๊ตฌํ์ฒด'๋ฅผ ์ฐ๊ฒฐํด์ผํ๋ค. ์ค์ ์์ ์ ๋ถ๋ฆฌํ ์ ์๋ค. ์์ ์ ๋ถ๊ฐํผํ๋ค.
// ์ธํฐํ์ด์ค๋ฅผ ํตํด ๊ฒฐํฉ๋(์์กด๊ด๊ณ)๋ฅผ ์ ์ฐํ๊ฒ ๋ง๋ค์๋ค.
interface MemberRepository{...}
interface DiscountPolicy{...}
Class MemoryMemberRepository implement MemberRepository{...}
Class FixDiscountPolicy implement DiscountPolicy{...}
// ํ์ง๋ง ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋ค, ๊ฒฐ๊ตญ ์ธ์ ๊ฐ๋ ๊ตฌํ์ฒด๋ฅผ ์ง์ ์ฐ๊ฒฐํด์ฃผ์ด์ผ ํ๋ค.
// ๊ตฌํ์ฒด๊ฐ ๋ฐ๋๋ค๋ฉด? ๊ธฐ์กด์ ์์ฑ & ์ค์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผํ๋ค. ์ ํ ์๊ด์๋ ๊ฐ์ฒด๋ผ๊ณ ํ๋๋ผ๋
private final MemberRepository memberRepository = new MemoryMemberRepository();
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
@๊ฐ์ 3. ๊ด๊ณ, ์ค์ ์ฑ ์์ ๋ถ๋ฆฌ
๊ทธ๋ผ ์์ [๊ฐ์ฒด๋ฅผ ์์ฑ, ์ค์ ํ๋ ์์ญ]๊ณผ [๋ก์ง ์คํ์์ญ]์ ๋ถ๋ฆฌํ ์๋ ์์๊น?
-> ์์กด์ฑ ์ฃผ์ (DI, Dependency Injection), ๊ตฌํ์ฒด๋ ๋๊ฐ ์์์ ๋ฃ์ด๋ผ. ๋ ์ธํฐํ์ด์ค๋ง ์์กดํด์ ์ฌ์ฉํ๊ฒ ๋ค.
public class OrderService {
// ์ฌ์ฉํ๋ ๊ฐ์ฒด์์๋ ๊ตฌํ์ฒด๋ฅผ ์์ฑ, ์ค์ ํ์ง ์๋๋ค.
public final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
// ๋๊ฐ ์์์ ๊ฐ์ฒด ์์ฑํด์ ๋ฃ์ผ๋ ด. ๋ ์ธํฐํ์ด์ค๋ง ๋ณด๊ณ ์ฌ์ฉํฉ๋๋ค.
public MemberServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
// ๊ฐ์ฒด ์์ฑ, ์ฆ ์์กด์ฑ ์ฃผ์
์ ๋ด๋นํ๋ '์ค์ '์ ๋ด๋นํ๋ ๊ฐ์ฒด
// ์ด๋ฅผ IoC ์ปจํ
์ด๋, DI ์ปจํ
์ด๋๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.
public class AppConfig {
// Repository
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
// DiscountPolicy
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
// OrderService
public OrderService orderService() {
return new OrderServiceImpl(
this.memberRepository(),
this.discountPolicy()
);
}
}
์ด๋ฐ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ ๊ฒ์ ์ ๋ตํจํด์ด๋ผ๊ณ ํ๋ค.
- ์ ๋ต ํจํด(strategy pattern)
์ ์ฑ (Policy) ํจํด์ด๋ผ๊ณ ๋ ํ๋ฉฐ ์๊ณ ๋ฆฌ์ฆ(๊ตฌํ์ฒด)์ ํ์์ ๋ฐ๋ผ ์ ๋ต์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์๊ฒ ํ๋ ํจํด.
์ฆ ์คํํ๋ฆ(Context)์์ ์์ ํน์ ๋ถ๋ถ์ ํด๋์ค(Startegy)๋ก ๋ถ๋ฆฌ์์ผ ํ์ฅ์ฑ๊ณผ ๋คํ์ฑ์ ๊ตฌํํ ๊ฒ.
public interface DiscountPolicy { // ์ธํฐํ์ด์ค๋ง ์์กดํ๋๋ก ํด๋ผ์ด์ธํธ๋ฅผ ์ค๊ณ.
double calculateWithDisCountRate(Item item);
}
// ํ์ํ ์๊ณ ๋ฆฌ์ฆ์ ์ํฉ์ ๋ง์ถฐ ์ ํ
public class FirstCustomerDiscount implements DiscountPolicy{
@Override // ๋ฐฉ๋ฒ1.
public double calculateWithDisCountRate(Item item) {
return item.getPrice() * 0.9;
}
}
public class LastCustomerDiscount implements DiscountPolicy{
@Override // ๋ฐฉ๋ฒ2.
public double calculateWithDisCountRate(Item item) {
return item.getPrice() * 0.8;
}
}
public class UnFreshFruitDiscount implements DiscountPolicy{
@Override // ๋ฐฉ๋ฒ3.
public double calculateWithDisCountRate(Item item) {
return item.getPrice() * 0.8;
}
}
@๊ฐ์ 4. ์ ์ด์ ์ญ์ (IoC)
์ด๋ @๊ฐ์ 3๊ณผ ๋์์ ์งํ๋์๋ค. ๊ธฐ์กด์ ์ฝ๋์์๋ ์ค์ ๋ถ๋ถ (๊ฐ์ฒด๋ฅผ ์์ฑ, ์์กด์ฑ ์ฃผ์ , ๋ฐํ)๋ถํฐ ํ๋ก๊ทธ๋จ์ด ์คํ๋๊ณ ์ข ๋ฃ๋๋ ๋ฉ์ธ์ค๋ ๋์ ํ๋ฆ๊น์ง ์ฐ๋ฆฌ๊ฐ ์ง์ ์กฐ์ข ํ์๋ค.
ํ์ง๋ง ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ๊ณ ์์กด์ฑ์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์, ์ด์ ๋ ์ด์ ๊ฐ์ฒด๋ ํ๋ก๊ทธ๋จ์ ์คํ๊ณผ์ ์ ์ํฅ์ ๋ผ์น์ง ์๋๋ค. ๋จ์ง '๊ฐ์ฒด'๊ฐ ๋งก์ ์ฑ ์์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ๋ก์ง์ ์คํํ ๋ฟ์ด๋ค. ๊ฐ์ฒด๋ ์ฑ ์คํ์ ์ ์ด๊ถ์ ๊ฐ์ง๊ณ ์์ง ์๋ค. ์ด๋ ๊ฒ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ ๊ตฌ์กฐ๊ฐ ๋ค๋ฐ๋๋ ๊ฒ์ ์ ์ด์์ญ์ (IoC, Inverse of Control)์ด๋ผ๊ณ ํ๋ค.
์ฌ์ค ์ ์ด์ ์ญ์ ๊ฐ๋ ์ ๊ณผ๊ฑฐ๋ถํฐ ํญ๋๊ฒ ์ ์ฉ๋์ด ์์๋ค. ์๋ฐ์ ์๋ธ๋ฆฟ์ ์๊ฐํด๋ณด์. ์ผ๋ฐ์ ์ผ๋ก ํ๋ก๊ทธ๋จ์ main()๋ฉ์๋๋ฅผ ํตํด ๊ฐ๋ฐ์๊ฐ ์ง์ ์ฑ์ ์ ์ด๊ถ์ ๊ฐ์ง๋ค. ํ์ง๋ง ์๋ธ๋ฆฟ์ ํตํ ๊ฐ๋ฐ์, ๊ฐ๋ฐ์๋ ์๋ธ๋ฆฟ ๊ฐ์ฒด์ ์ฑ ์์ ์ ํ๊ณ ๊ทธ ์ฑ ์์ ๋ง๋ ๋น์ฆ๋์ค ๋ก์ง์ ๊ตฌํํ ๋ฟ์ด๋ค. ์ด ๊ฐ์ฒด๊ฐ ์ธ์ ์ด๋์ ์ฌ์ฉ๋ ์ง ํ๋ก๊ทธ๋จ์ด ์ด๋ป๊ฒ ์คํ๋๋์ง๋ ๊ฐ๋ฐ์๊ฐ ์ ์ ์๋ค. WAS๊ฐ ๋ด๋นํ ๋ฟ. ์ ์ด๊ถ์ด ์ญ์ ๋์ด์๋ค.
์คํ๋ง์์๋ ์ ์ด์ ์ญ์ ์ ์ด๋ ๊ฒ ์ค์ ์ปจํ ์ด๋(AppConfig ๊ฐ์ฒด)๊ฐ ์์กด์ฑ ์ฃผ์ ์ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ๋ค. ๊ทธ๋์ ๋ฒ์ฉ์ ์ธ ๋จ์ด์ธ [IoC ์ปจํ ์ด๋] ๋์ ์ ์๋ฏธ๋ฅผ ๋ช ํํ๊ฒ ํ ๋ ค๊ณ ์์กด์ฑ ์ฃผ์ (DI, Dependency Injection) [DI ์ปจํ ์ด๋]๋ผ๋ ์ฉ์ด๋ฅผ ์ฌ์ฉํ๋ค. ์ด ๋๊ฐ๋ ๊ฐ์ ์ปจํ ์ด๋๋ฅผ ์๋ฏธํ๋ค.
# ์ค๋ธ์ ํธ ํฉํ ๋ฆฌ๋ฅผ ์ด์ฉํ ์คํ๋ง IoC
@ Application Context์ ์ค์ ์ ๋ณด
์ด์ ์คํ๋ง์์ ์ด๋ฅผ ์ด๋ป๊ฒ ํ์ฉํ๋์ง ์์๋ณด์. ์คํ๋ง์์๋ ์ง์ ๋ง๋ค๊ณ ๊ด๊ณ๋ฅผ ๋ถ์ฌ๋ฐ๋ ๊ฐ์ฒด๋ค์ ์คํ๋ง ๋น(Bean)์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ์๋ ์ ์ํฐํ๋ผ์ด์ฆ ์๋ฐ๋น(EJB)์์ ์ฌ์ฉํ ๊ฐ์ฒด๋จ์์ ์ปดํฌ๋ํธ์ ๋น์ทํ ์๋ฏธ๋ก ์ฌ์ฉ๋๋ค.
์ฆ ์คํ๋ง ๋น์ ์ฑ์์ ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ์ด๋ฉด์ ์คํ๋ง ์ปจํ ์ด๋(DI ์ปจํ ์ด๋)๊ฐ ๊ฐ์ฒด์์ฑ, ์์กด๊ด๊ณ์ค์ , ์ฌ์ฉ๋ฑ์ ์ ์ดํด์ฃผ๋ IoC๊ฐ ์ ์ฉ๋ ์ค๋ธ์ ํธ๋ฅผ ๊ฐ๋ฅดํค๋ ๋ง์ด๋ค. ์คํ๋ง์์๋ ์ด๋ฌํ ์์ฑ, ๊ด๊ณ์ค์ ์ ๋ด๋นํ๋ IoC ๊ฐ์ฒด๋ฅผ ๋น ํฉํ ๋ฆฌ(Bean Factory)๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํ์ง๋ง BeanFactory๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ์๋ค. ์ด๋ฅผ ์์ํ ApplicationContext๋ฅผ ์คํ๋ง ์ปจํ ์ด๋๋ก ์ฌ์ฉํ๋ค. BeanFactory์์๋ ์์์ ์ค๋ช ํ IoC์ ๊ฐ์ฒด์์ฑ, ์ค์ ๋ถ๋ถ์ด ์ ์๋์ด์๋ค๋ฉด ApplicationContext๋ ์ด๋ฅผ ํฌํจํ ๋ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ ๊ฐ์ง๊ณ ์๋ค. ์ค์ ์ฌ์ฉํ ๋์๋ ์๋์ ๊ฐ์ด ํ์ํ ์คํ๋ง๋น์ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
// ์ฐธ๊ณ ๋ก ์ค์ ๊ฐ์ฒด(AppConfig) ๋ํ ์คํ๋ง ์ปจํ
์ด๋์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํด์ ์ฌ์ฉํ๋ค.
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// ์คํ๋ง ์ปจํ
์ด๋๋ key-map ๊ตฌ์กฐ๋ก ๋ฌธ์์ด๋ก ๊ตฌ๋ถํ์ฌ ๋ฑ๋ก๋๋ค.
// UserDao ํ์
์ "userDao"๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง ์คํ๋ง ๋น์ ์ฃผ์
๋ฐ๋ ์ฝ๋.
UserDao dao = context.getBean("userDao", UserDao.class);
// Object.class ๋ ํด๋น ํด๋์ค์ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ์ด ํ์ํ ๋ ๊ฐ์ฒด ์์ฑ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค์ด์ค๋ค.
// ์ด๋ฌํ ๊ธฐ์ ์ ์๊ธฐ์์ ์ ์ค๊ณ๋(class)๋ฅผ ๋ณต์ ํด์ ๋๊ธฐ๋, ๋ฆฌํ๋ ์
๊ธฐ์ ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
// ๊ฐ์ฒด๋ฅผ ๋ฌธ์์ด("userDao")๋ก ๊ตฌ๋ถ์ง์ด ์ฌ์ฉํ ์ ์๋ ์ด์ ๋ ์ด๋ฌํ ๋ฆฌํ๋ ์
๊ธฐ์ ๋๋ถ์ด๋ค.
App..Context์ ๊ตฌํ์ฒด๋ฅผ ์ด๋ ธํ ์ด์ (AnnotationConfigApp...Context)๋ก ์ ํ์ผ๋, ์ฐ๋ฆฐ ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ์คํ๋ง์์ ์ค์ ์ ๋ณด๋ฅผ ์ง์ ํ ์ ์๋ค. ์ปจํ ์ด๋ ์ค์ ์ ๋ณด๋ฅผ ๋ด๋ ๊ฐ์ฒด์ @Configuration ํ๊ทธ๋ฅผ ๋ฌ๋ฉด๋๋ค. ์์์ ๋งํ์ง๋ง ์ด ๊ฐ์ฒด(AppConfig) ๋ํ ์คํ๋ง ๋น์ผ๋ก ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ ๊ฐ์ฒด๋ค์ @Bean ๋ฉ์๋๋ฅผ ํตํด ์์ฑํ๋ฉด ๋๋ค. @Bean ํ๊ทธ๋ ๋ฉ์๋์๋ง ์ ์ ์ ์์ผ๋ฉฐ ํด๋น ๋ฉ์๋๊ฐ ๋ฐํํ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
@Configuration
public class AppConfig {
@Bean // ์ด๋ฆ์ ์ง์ ํ์ง ์์ผ๋ฉด ๋ฐํ ๊ฐ์ฒด ์ด๋ฆ์ธ "memberRepository"๋ก ์๋์ค์ ๋๋ค.
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean(name="myCustomBean") // ๋ฌผ๋ก ์ด๋ ๊ฒ ์ง์ ํ ์ ์์ผ๋, ๊ฑฐ์ ์ฌ์ฉํ์ง ์๋๋ค.
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
@Bean // ["orderService", OrderService.class] ๋ฅผ ๊ฐ์ง ์คํ๋ง ๋น์ด ์์ฑ๋จ.
public OrderService orderService() {
return new OrderServiceImpl(
this.memberRepository(),
this.discountPolicy());
}
}
์ฌ๋ฐ๋ ์ ์ @Configuration ๊ฐ์ ํ๊ทธ๊ฐ ์๋๋ผ๋ @Bean์ผ๋ก ์คํ๋ง๋น์ ๋ฑ๋กํ ์ ์๋ค๋ ์ ์ด๋ค. ๊ทธ๋ผ ํด๋น ํ๊ทธ๋ ์ ์ ๋๊ฑธ๊น? ๊ทธ๋ฅ ํท๊ฐ๋ฆฌ์ง๋ง๋ผ๊ณ ์ ๋๊ฑธ๊น? ๋น์ฐํ ์๋๋ค. @Configuration์ ํด๋น ๊ฐ์ฒด๊ฐ ์ค์ ๊ฐ์ฒด(AppConfig)์์ ์คํ๋ง์๊ฒ ์๋ ค์, ์ฑ๊ธํค์ ๊ตฌํํ ์ ์๊ฒ ๋ง๋ค์ด์ค๋ค.
์ฑ๊ธํค์ ๊ฐ์ ๊ฐ์ฒด๊ฐ 1๋ฒ๋ง ์์ฑ๋๋๋ก ๋ง๋ค์ด์ ๋๋ ค์ฐ๋ ๊ฒ์ ๋งํ๋๋ฐ, ์๋์ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ดํด๊ฐ ์ฝ๋ค. ์๋์ ๊ฐ์ด @Configuration ์์ด ์์ฑํ๊ฒ๋๋ฉด ๋์ผํ ๊ฐ์ฒด๋ฅผ ์คํ๋ง๋น์ผ๋ก ์ฌ๋ฌ๋ฒ ์ค๋ณตํด์ ๋ฑ๋กํ๊ฒ ๋๋ค.
public class AppConfig {
@Bean
public MemberService memberService() {
// MemberService๊ฐ์ฒด๋ ๋น์ผ๋ก 1๋ฒ ์์ฑ๋จ, Repository() ๋ฅผ ํธ์ถํด์ ์์กด์ฑ ์ฐ๊ฒฐ
System.out.println("call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
// OrderSerivce ๊ฐ์ฒด๋ ๋น์ผ๋ก 1๋ฒ ์์ฑ๋จ. Repository()๋ฅผ ํธ์ถํด์ ์์กด์ฑ ์ฐ๊ฒฐ
System.out.println("call AppConfig.orderService");
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
// ?? ์ฌ๋ฌ๋ฒ ํธ์ถํ๋๋ฐ ๊ทธ๋ผ ๋๋ ์คํ๋ง ๋น์ผ๋ก ๋ช๊ฐ๋ฅผ ์ค๋ณตํด์ ๊ฐ์ง๊ณ ์๋๊ฑฐ์ผ?
return new MemoryMemberRepository();
}
}
์ด๊ฒ ์ด๋ป๊ฒ ๊ฐ๋ฅํ๊ฑธ๊น? @Configuration์ ๋ฌ๋ฉด ์คํ๋ง ์ปจํ ์ด๋์์ ๊ฐ์ฒด ์์น์ถ์ ์ด๋ผ๋ ํด์ ์ค๋ณต ์์ฑํ์ง ๋ชปํ๊ฒ ๋ง๋ค์ด์ฃผ๋ ๊ฑธ๊น?
# ์คํ๋ง Application Context์ ๋์๋ฐฉ์
์ปจํ ์ด๋๋ฅผ ๊ตฌํํ ๋ ์ค์ ๊ฐ์ฒด๊ฐ ์์ฑํ๋ ๋ฐฉ์๊ณผ (=Object Factory)ํ๋ ๋ฐฉ์๊ณผ ์คํ๋ง์์์ App..Context์ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง ์์๋ณด์.
- ํด๋ผ์ด์ธํธ๋ ๊ตฌ์ฒด์ ์ธ ํฉํ ๋ฆฌ ํด๋์ค(์์ฑ, ์ค์ ์ ๋ณด)๋ฅผ ์ ์ ์๊ณ , ์ ํ์๋ ์๋ค.
- App..Context๋ ์ฑ ์ ์ฒด์ ์ข ํฉ์ ์ธ IoC ์๋น์ค๋ฅผ ์ ๊ณตํด์ค๋ค.
- App..Context๋ ๋ฑ๋ก๋ ์๋น์ค ๊ฐ์ฒด(์คํ๋ง๋น)๋ฅผ ํธํ๊ฒ ์ฃผ์ ํ ์ ์๋๋ก ๋ค์ํ ๊ฒ์ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ค.
๊ธฐ์กด์ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค์๋ AppConfig(๋๋ UserDaoFactory)๋ ๋จ์ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํ์ํ ๊ด๊ณ๋ฅผ ๋งบ์ด์ฃผ๋ ์ ํ์ ์ธ ์ญํ ์ ํ๋๋ฐ ๋ฐํด, ์คํ๋ง์ App...Context๋ ์ ์ฒด ์ฑ ์์ฒด์ IoC๋ฅผ ์ ์ฉํ์ฌ ์๋น์ค์ ์ฌ์ฉํ๋ ๋ชจ๋ ์ค๋ธ์ ํธ์ ๋ํ ์์ฑ๊ณผ ๊ด๊ณ์ค์ ์ ๋ด๋นํ๋ค. ๋ํ DaoFactory์ ๋ฌ๋ฆฌ ์๋ฐ์ฝ๋๋ก ๊ด๊ณ๋ฅผ ์ง์ ๋งบ๋ ๊ฒ์ด ์๋๋ผ ์ฝ๋์ ๋ถ๋ฆฌ๋ ์ค์ ์ ๋ณด(@Bean)๋ฅผ ์ด์ฉํ์ฌ ๊ฐ๋ฐ์ ์ฝ๋์ ๋ณ๋๋ก ์กด์ฌํ๋ ์คํ๋ง์ ์ค๋ธ์ ํธ ํฉํ ๋ฆฌ์ ๊ทธ ์์ ์ ์์ํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ๋ค ์ฌ์ฉํ๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ @Bean ์ด ๋ถ์ ๋ฉ์๋์ ๋ฐํ๊ฐ์ ์คํ๋ง๋น์ผ๋ก ๋ง๋ ๋ค.
๊ทธ๋ฆฌ๊ณ @Bean ๋ฉ์๋๋ฅผ ๋ชจ์๋์ AppConfig ๊ฐ์ฒด์ @Configuration์ ์ฌ์ฉํ๋ฉด ๊ฐ์ฒด๋ค์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๊ณ , ๊ฐ ๊ฐ์ฒด๋ฅผ ์ฑ๊ธํค์ผ๋ก ์ ์งํ์ฌ ์คํ๋ง ๋น ์ค๋ณต ์์ฑ์ ๋ฐฉ์งํด์ค๋ค. (์ค์ ์ ํตํด ๋ฐ๊ฟ ์ ์๋ค. ๊ธฐ๋ณธ๊ฐ์ด ์ฑ๊ธํค)
@ ์คํ๋ง์์ ์ฑ๊ธํค์ ๋ง๋๋ ๋ฐฉ๋ฒ
์คํ๋ง์ CGLIB๋ผ๋ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ์ฌ ์ฑ๊ธํค์ ๊ตฌํํ๋ค. ์ค์ ์ปดํ์ผํ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด AppConfig.class ๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋๋๊ฒ ์๋๋ผ AppConfig@CGLIB ๋ผ๋ ์์๋ฐ์ ํด๋์ค๊ฐ ์ฌ์ฉ๋๋ค.
// CGLIB๋ ์๋ฐ์ฝ๋๊ฐ ์๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์ง์ ์กฐ์ํ๊ธฐ์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ด ์ด๋ ต๊ณ ๋ณต์กํ๋ค.
// ์ดํด๋ฅผ ๋๊ธฐ์ํด ์๋ฐ์ฝ๋๋ก ๋น์ ํ๋ฉด ์๋์ ๊ฐ์ด ๋์ํ๋ค.
class AppConfig@CGLIB123 extends AppConfig{
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository๊ฐ ์ด๋ฏธ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก๋์ด ์์ผ๋ฉด?) {
return ์คํ๋ง ์ปจํ
์ด๋์์ ์ฐพ์์ ๋ฐํ;
} else { //์คํ๋ง ์ปจํ
์ด๋์ ์์ผ๋ฉด
๊ธฐ์กด ๋ก์ง์ ํธ์ถํด์ MemoryMemberRepository๋ฅผ ์์ฑํ๊ณ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก
return ๋ฐํ
}
}
... ์๋ต ...
}
# ์คํ๋ง IoC ์ฉ์ด์ ๋ฆฌ
ํท๊ฐ๋ฆฌ์ง ์๋๋ก ์คํ๋ง์์ ์ ๊ณตํ๋ IoC ์ปจํ ์ด๋(DI ์ปจํ ์ด๋)์ ๊ด๋ จ๋ ์ฉ์ด๋ค์ ์ ๋ฆฌํด๋ณด์.
- IoC์ DI
- ์ ์ด์ ์ญ์ (Inverse of Control)์ ์ฑ์ ์คํํ๋ฆ(๊ฐ์ฒด๋ฅผ ์์ฑ, ์ค์ , ํ์)์ ์๋น์ค ๊ฐ์ฒด(๊ฐ๋ฐ์)๊ฐ ์๋ ์ธ๋ถ(์คํ๋ง)์์ ๊ด๋ฆฌํ๋ ๊ฒ์ ์๋ฏธํ๋ค. ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ์ ๊ฐ์ฅ ํฐ ์ฐจ์ด์ ์ด๊ธฐ๋ ํ๋ค.
- ์์กด์ฑ ์ฃผ์ (Dependency Injection)์ IoC๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ ์ค ํ๊ฐ์ง๋ก, ์คํ๋ง IoC์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค. IoC๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์๋ DI ๋ง๊ณ ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค๋ ๊ฑฐ๋ง ์ธ์งํ๊ณ ์์. - Bean (๋น)
- ๋น ๋๋ ๋น ๊ฐ์ฒด๋ ์คํ๋ง์ด ์ปจํ ์ด๋๋ฅผ ํตํด IoC๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค. ์ฃผ์ํ ์ ์ ์คํ๋ง์์ ์ฌ์ฉํ๋ ๋ชจ๋ ๊ฐ์ฒด๊ฐ ๋น์ธ ๊ฒ์ด ์๋๋ผ, ์คํ๋ง์ด ์ง์ ์์ฑ๊ณผ ์ ์ด๋ฅผ ๋ด๋นํ๋ ์ค๋ธ์ ํธ๋ง ๋น์ด๋ผ๊ณ ํ๋ค. - Bean Factory(๋น ํฉํ ๋ฆฌ)
- ์์์ ๋ง๋ค์๋ AppConfig ๊ฐ์ฒด๋ฅผ Object-Container๋ผ๊ณ ๋ถ๋ฅด๋ ๊ฒ ์ฒ๋ผ ์คํ๋ง์ IoC๋ฅผ ๋น๋นํ๋ ํต์ฌ ์ปจํ ์ด๋๋ฅผ ์๋ฏธํ๋ค. ๋ณดํต์ ๋น ํฉํ ๋ฆฌ๋ฅผ ๋ฐ๋ก ์ฌ์ฉํ์ง ์๊ณ ์ด๋ฅผ ์์ก๋ฐ์ App...Context ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ ์ฌ์ฉํ๋ค. - Application Context(์ฑ ์ปจํ
์คํธ)
- ๋น ํฉํ ๋ฆฌ๋ฅผ ์์๋ฐ์ ํ์ฅํ IoC ์ปจํ ์ด๋๋ค. ๋น ํฉํ ๋ฆฌ์์๋ ๊ฐ์ฒด์ ์์ฑ๊ณผ ๊ด๋ฆฌ๋ง์ ๋ด๋นํ์๋ค๋ฉด, ์ฑ ์ปจํ ์คํธ๋ ์คํ๋ง์ด ์ ๊ณตํ๋ ๊ฐ์ข ๋ถ๊ฐ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐ๋ก ์ ๊ณตํ๋ค. - Configuration Metadata(์ค์ ์ ๋ณด, ๋ฉํ์ ๋ณด)
- ์ฑ ์ปจํ ์คํธ(๋น ํฉํ ๋ฆฌ)๋ฅผ ์ค์ ํ๊ธฐ ์ํ ๋ฉํ์ ๋ณด๋ฅผ ์๋ฏธํ๋ค. ์ ๋ง ์คํ๋ง์ ํ์ํ ์ค์ ์ ๋ณด๋ฅผ ์ ๋ ๊ฒฝ์ฐ๋ ์์ง๋ง, ๋ณดํต์ IoC ์ปจํ ์ด๋์ ์ํด ๊ด๋ฆฌ๋ ๊ฐ์ฒด๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํด ๋ง์ด ์ฌ์ฉํ๋ค.
- ์ฐธ๊ณ ๋ก ์คํ๋ง์ ๋ค์ํ ๋ฐฉ์์ผ๋ก ์ค์ ์ ๋ณด๋ฅผ ์์ฑํ ์ ์๋ค. ์๋ ์๋ xml๋ฐฉ์์ผ๋ก ๋ง์ด ์์ฑํ์๋๋ฐ, ์์ฆ์ ์ค์ ํ์ผ์ ๋ถ๋ฆฌํ์ง ์๊ณ ์๋ฐ์ฝ๋์ ๋ฐ๋ก ์ ์ ์ ์๋ ์ด๋ ธํ ์ด์ ๋ฐฉ์(@Configuration)๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๋ค. - Container (DI ์ปจํ
์ด๋)
- IoC ๋ฐฉ์์ผ๋ก ๋น ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ค๋ ์๋ฏธ์์ ์์ [์ฑ ์ปจํ ์คํธ, ๋น ํฉํ ๋ฆฌ]๋ฅผ IoC ์ปจํ ์ด๋๋ผ๊ณ ๋ถ๋ฅด๊ธฐ๋ ํ๋ค. ์ดํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ๋ผ๊ณ ํ๋ ๊ฒ ๋ณด๋ค IoC ์ปจํ ์ด๋๋ผ ๋ถ๋ฅด๋๊ฒ ๋ ์๋ฏธ๊ฐ ์ ํํ๊ฒ ์ ๋ฌ๋๋ ํจ๊ณผ๋ ์๋ค.
- ๋ค๋ง IoC๋ผ๋ ์ฉ์ด๋ ๋ฒ์ฉ์ ์ธ ๋จ์ด์ด๊ธฐ์, ์คํ๋ง์์๋ IoC๋ฅผ DI๋ก ๊ตฌํํ๋ค๋ ์๋ฏธ์์ DI ์ปจํ ์ด๋๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค. ์ด ๋์ ๊ฐ์ ๋จ์ด์ด๋ค. ์ ํํ๋ Dependency Injection์ ํตํด IoC๋ฅผ ๊ตฌํํ ์ปจํ ์ด๋๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค. - Spring Core (์คํ๋ง ํ๋ ์์ํฌ)
์คํ๋ง ํ๋ ์์ํฌ๋ IoC ์ปจํ ์ด๋(์ฑ ์ปจํ ์คํธ)๋ฅผ ํฌํจํด์ ์คํ๋ง์ด ์ ๊ณตํ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ํตํ์ด ๋งํ ๋ ์ฃผ๋ก ์ฌ์ฉํ๋ค. ๋ณดํต Spring Core๋ผ ํจ์ ์ฑ์ ๋ง๋๋๋ฐ ์ฌ์ฉํ๋ ํต์ฌ๊ธฐ๋ฅ๋ค (IoC์ปจํ ์ด๋, AOP, ์ด๋ฒคํธ๋ฑ)์ ์๋ฏธํ์ง๋ง ๋ณดํต '์คํ๋ง'์ด๋ผ ํ๋ฉด ์คํ๋ง ์งํ์์ ์ ๊ณตํ๋ ๋ค๋ฅธ ๊ธฐ๋ฅ๋ค์ ํฌํจํ ์๋ฏธ๋ก ๋ง์ด ์ฌ์ฉํ๋ค.
์คํ๋ง ํ๋ ์์ํฌ์์๋ ํ์์ ๋ฐ๋ผ ๊ธฐ์ (๋๊ตฌ)๋ค์ ๊ณจ๋ผ์ ์ฌ์ฉํ ์ ์๋๋ก ์ ๊ณตํด์ค๋ค. ์์ฃผ ์ฌ์ฉํ๋ ํต์ฌ๊ธฐ๋ฅ๋ค ์ด์ธ์๋ ํ์ ์๋น์ค์ ํ์ํ ๊ฑฐ์ ๋ชจ๋ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ค.
#IoC์ ์๋ฏธ
IoC๋ ์ํํธ์จ์ด์์ ์์ฃผ ๋ฐ๊ฒฌํ ์ ์๋ ์ผ๋ฐ์ ใ ๋ ๊ฐ๋ ์ด๋ค. ๊ฐ์ฒด์งํฅ์ ์ค๊ณ, ๋์์ธ ํจํด, ๊ทธ๋ฆฌ๊ณ ์ปจํ ์ด๋์์ ๋์ํ๋ ์๋ฒ๊ธฐ์ ์ ๋์ํ๋ค๋ฉด ์์ฐ์ค๋ฝ๊ฒ IoC๋ฅผ ์ ์ฉํ๊ฑฐ๋ ๋น์ทํ ์๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค.
๊ทธ๋์ IoC๋ผ๊ณ ๋จ์ ์นญํ๊ฒ๋๋ฉด ์๋ธ๋ฆฟ ์ปจํ ์ด๋์ฒ๋ผ ๋์ํ๋ ์๋น์ค ์ปจํ ์ด๋๋ฅผ ์๋ฏธํ๋ ๊ฑด์ง, ํ ํ๋ฆฟ ๋ฉ์๋ ํจํด์ ์ด์ฉํ๊ฑด์ง, ์๋๋ฉด ๋ ๋ค๋ฅธ IoC ๊ธฐ์ ์ธ๊ฑด์ง ์๋ฏธ๊ฐ ๋ช ํํ์ง ์๊ธฐ์ ์คํ๋ง์์๋ DI ์ปจํ ์ด๋๋ผ๋ ๋ช ํํ ์ด๋ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
# ์์กด๊ด๊ณ ๊ฒ์๊ณผ ์ฃผ์
์คํ๋ง์์ ์ ๊ณตํ๋ IoC๋ ์ปจํ ์ด๋๊ฐ ์ค์ ์ ๋ณด๋ฅผ ์ฐธ์กฐํ์ฌ ์์กด๊ด๊ณ ์ฃผ์ (@Configuration, @Bean) ํด์ฃผ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, App..Context๋ฅผ ์ด์ฉํ์ฌ ์ง์ ์์กด๊ด๊ณ๋ฅผ ๊ฒ์(DL, Dependency Lookup)ํด์ ์ค์ ํ๋ ๋ฐฉ๋ฒ๋ ์ ๊ณตํด์ค๋ค.
public UserDao(){
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DaoFactory.class);
// getBean์ผ๋ก ์ง์ ์ํ๋ ๊ฐ์ฒด๋ฅผ ๊ฒ์ํด์ ์ฐ๊ฒฐ์ํจ๋ค.
this.connectionMaker = context.getBean("connectionMaker", ConnectionMaker.class);
}
์ด๋ ๊ฒ ํ๋ฉด ์ค์ ๊ฐ์ฒด(AppConfig)๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ์ง ์์๋ ๋๋ค๋ ์ฅ์ ์ด ์๊ธดํ๋, ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ๋ฐ๋ ์ชฝ์ด ํจ์ฌ ๋จ์ํ๊ณ ๊น๋ํ๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ DL์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค๋ ๊ฒ๋ง ์๊ณ ์ผ๋จ์ ๋์ด๊ฐ๋๋ก ํ์.
# ์คํ๋ง์ ์ ์ฐํจ, ๋ค์ํ ์ค์ ์ ๋ณด ์์ฑ๋ฐฉ๋ฒ
์คํ๋ง์ ์ด๋ ธํ ์ด์ , XML์ ํฌํจํ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ค์ ์ ๋ณด๋ฅผ ์ฝ์ด๋ค์ผ ์ ์๋ค.
ํ์ง๋ง ์คํ๋ง ์ปจํ ์ด๋์๋ ์ค์ ์ ๋ณด๋ฅผ '์ฝ๋ ์ธํฐํ์ด์ค'๋ง ์กด์ฌํ ๋ฟ, ์ด๋ป๊ฒ ์ฝ๋์ง๋ ์ ํ์์ง ์๋ค.
์คํ๋ง์์ ์ ๊ณตํ๋ ์ค์ ์ ๋ณด Reader ๊ตฌํ์ฒด, ๋๋ ๋ด๊ฐ ์ง์ ๋ง๋ Reader๋ฅผ ์ด์ฉํด BeanDefinition์ ๊ตฌํ๋ง ํ๋ฉด ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด๋ค. ์คํ๋ง ์์ฒด์ ์ฝ๋๋ฅผ ๋ณผ ์ผ์ ์๊ฒ ์ง๋ง, ์ด์ฒ๋ผ ์คํ๋ง ์์ฒด๋ ๊ฐ์ฒด์งํฅ์ ํ์ฉํด ์ ์ฐํ๊ฒ ๊ตฌ์ฑ๋์ด์๋ค๋ ๊ฒ๋ง ์๊ณ ๋์ด๊ฐ๋๋ก ํ์.
'๐ฑ Spring Framework > Spring Core' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ฝ๊ฒ ์ดํดํ๋ ์คํ๋ง AOP (~์์ฑ์ค~) (0) | 2021.08.18 |
---|---|
ํ ๋น์์คํ๋ง#2 ์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ์ ์ค๋ธ์ ํธ ์ค์ฝํ (0) | 2021.08.14 |
#11 ๋น ์ค์ฝํ(+Provider, ํ๋ก์ ๋ชจ๋) (0) | 2021.08.03 |
#10 ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ (0) | 2021.08.03 |
#9 ์์กด๊ด๊ณ ์๋์ฃผ์ ์์ ์๊ธฐ๋ ๋ฌธ์ (+Lombok ์๊ฐ) (0) | 2021.08.03 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev