✅ Java-Configuration 설정을 이용한 분리책에서는 xml 방식을 통해 DAO 객체와 SQL을 분리하고 있지만, 현재는 잘 쓰이지 않는 방식이기 때문에 Java-Configuration 방식을 사용해서 분리하도록 변경하였습니다. TestDaoFactory@Bean public UserDaoJdbc userDao() { UserDaoJdbc userDaoJdbc = new UserDaoJdbc(); userDaoJdbc.setDataSource(dataSource()); userDaoJdbc.setSqlMap(sqlMap()); //sqlMap Bean 객체 주입 return userDaoJdbc; } //== xml 방식이 아닌 java-configuration 방식을 사용 ==// @Bea..
✅ 자동 프록시 생성부가 기능이 타겟 오브젝트마다 새로 생성되는, 즉 InvocationHandler를 구현한 구체 클래스가 타겟 오브젝트에 종속되어 매번 새롭게 생성되는 것은 Advice를 통해서 해결했습니다. 이제 남은 것은 타겟 오브젝트를 변경할 때마다 거의 비슷한 내용의 ProxyFactoryBean의 빈 설정 정보를 매번 복사해서 등록해야 하는 문제입니다. target을 제외하면 Advisor 정보가 동일하기 때문에 중복을 제거할 수 있을 것입니다. 🔹빈 후처리기 -DefaultAdvisorAutoProxyCreatorBeanPostProcessor을 구현해서 만드는 빈 후처리기는 스프링 빈 오브젝트로 만들어지고 난 후에, 빈 오브젝트를 다시 가공할 수 있게 해줍니다. 여기서는 DefaultAd..
✅ ProxyFactoryBean스프링에서 프록시 오브젝트를 생성해주는 기술을 추상화한 팩토리 빈을 제공하고 있습니다. 스프링의 ProxyFactoryBean은 스프링 프레임워크에서 제공하는 기능 중 하나로, 동적 프록시를 생성하고 Bean으로 등록하여 관리하는 팩토리 빈(FactoryBean)입니다. ProxyFactoryBean을 사용하면 AOP(Aspect-Oriented Programming)를 구현하여 메소드 호출을 가로채고 부가적인 기능을 추가할 수 있습니다. 스프링에서 제공하는 팩토리 빈을 통해서, 기존에 작성했던 팩토리 빈의 한계를 극복할 수 있습니다. Advice: 타겟이 필요 없는 순수한 부가 기능Advice는 AOP에서 타겟 오브젝트에 적용하는 부가적인 기능을 담은 객체를 총칭합니다...
✅ 팩토리 빈(FactoryBean)스프링은 내부적으로 리플렉션 API를 이용해서 빈 정의에 나오는 클래스 이름을 가지고 Bean을 생성합니다. 문제는 다이나믹 프록시 오브젝트가 동적으로 클래스가 생성되기 때문에 어떤 클래스인지 조차 알 수 없어서 Bean에 등록할 수 없습니다. 다이내믹 프록시는 Proxy 클래스의 newProxyInstance() 라는 스태틱 팩토리 메소드를 통해서만 만들 수 있습니다. 이를 만들기 위해 스프링에서 제공하는 팩토리 빈 인터페이스를 구현하여서 빈 객체를 생성하는 방법을 알아보겠습니다. 🔹팩토리 빈 학습 테스트팩토리 빈팩토리 빈이란 스프링을 대신해서 오브젝트의 생성로직을 담당하도록 만들어진 특별한 빈을 말합니다. 가장 간단한 방법은 스프링의 FactoryBean이라는 인터..
✅ 프록시단순히 확장성을 고려해서 한 가지 기능을 분리한다면 아래와 같이 전략 패턴을 사용해도 됩니다. 트랜잭션 기능은 추상화 작업을 통해 전략 패턴을 적용하였지만 여전히 트랜잭션을 적용한다는 코드가 남아있었습니다. 트랜잭션이라는 기능은 사용자 관리 비즈니스 로직과는 성격이 다르기 때문에 아예 그 적용 사실 자체를 밖으로 분리할 수 있습니다. 이 방법을 이용해 UserServiceTx를 만들었고, UserServiceImpl에는 트랜잭션 코드가 하나도 남아있지 않게 되었습니다. 하지만 이렇게 구성했더라고 클라이언트가 핵심기능을 가진 클래스를 직접 사용해버리면 부가 기능을 가진 클래스를 따로 빼두었기 때문에 부가 기능이 적용되지 않습니다. 그래서 부가 기능이 마치 자신이 핵심 기능을 가진 클래스처럼 꾸미기..
✅ 복잡한 의존관계 속 테스트가장 편하고 좋은 테스트 방법은 가능한 한 작은 단위로 쪼개서 테스트하는 것입니다. 작은 단위의 테스트가 좋은 이유는 테스트가 실패했을 때 그 원인을 찾기 쉽기 때문입니다. UserService는 엔터프라이즈 시스템의 복잡한 모듈과는 비교할 수 없을 만큼 간단한 기능만을 갖고 있습니다. 그럼에도 UserService의 구현 클래스들이 동작하기 위해서는 세 가지 타입의 객체가 필요합니다. UserDao 타입의 객체를 통해 DB와 데이터를 주고받아야 하고, MailSender를 구현한 객체를 이용해 메일을 발송해야 합니다. 마지막으로 트랜잭션 처리를 위해 PlatformTransactionManager와 커뮤니케이션이 필요합니다. UserServiceTest를 테스트하고자 하는 ..
💡AOP는 "Aspect-Oriented Programming"의 약어로, 한글로는 "관점 지향 프로그래밍"이라고 불립니다. ✅ 메소드 분리 트랜잭션 경계설정 코드와 비즈니스 로직 코드가 복잡하게 얽혀있는 것처럼 보이지만, 코드 간의 서로 주고 받는 정보가 없이 뚜렷하게 구분되어짐이 보입니다. 성격이 다른 두 코드를 메소드 추출 기법으로 분리해보겠습니다. 💡기존 Policy를 따로 구현해서 DI 받던 코드를 제거하고 제일 깔끔한 코드로 다시 돌아왔습니다. 학습 중에 너무 복잡해져서 되돌아왔기 때문에 이전의 작성된 글들과 코드가 많이 다를 수 있습니다. 자세한 것은 github com.jhcode.spring.ch6 부분을 참고해주시기 바랍니다. UserService//TransactionManger을 외..
✅ 수직 수평 계층 구조와 의존 관계 UserService와 UserDao는 애플리케이션의 로직을 담고 있는 애플리케이션 계층입니다. UserDao는 데이터를 어떻게 가져오고 등록할 것인가에 대한 데이터 액세스 로직을 담고 있습니다. UserSerice는 순수하게 사용자 관리의 업무 비즈니스 로직을 담고 있습니다. UserDao와 UserService는 인터페이스와 DI를 통해 연결됨으로써 결합도가 낮아졌습니다. UserDao는 DB를 연결을 생성하는 방법에 대해 DataSource 인터페이스를 활용하여 결합도가 낮아졌습니다. UserService의 트랜잭션 기술도 스프링이 제공하는 PlatformTransactionManager 인터페이스를 통한 추상화를 활용하여 결합도가 낮아졌습니다. 👉 이렇게 스프..
모든 사용자에 대해 업그레이드 작업을 진행하다가 중간에 예외가 발생해서 작업이 중단된다면 어떻게 될까요? 이미 변경된 사용자의 레벨은 작업 이전 상태로 돌아갈까요? 아니면 바뀐 채로 남아있을까요? 이를 확인해보기 위해 1초도 안 걸리는 짧은 사용자 레벨 업그레이드 과정에서 네트워크가 끊긴다거나 DB 서버가 다운되거나 하는 상황을 직접 구현하는 것은 어렵습니다. 그렇기 때문에 해당 상황이 발생했을 때의 오류 중 일부를 임의로 던져서 해당 로직을 멈추는 방법으로 재현해보겠습니다. UserService의 기능을 그대로 사용해야 하고, 테스트에 필요한 로직도 더 필요한 상황입니다. UserService의 코드를 복붙하여 새로운 클래스를 만들 수도 있지만 코드 중복도 발생하고, 사용하기도 번거롭기 때문에 User..
✅ UserService.add()처음 가입하는 사용자는 기본적으로 BASIC 레벨이어야 한다는 로직을 어디에 담아야 할까요? UserDaoJdbc는 주어진 User 오브젝트를 DB에 정보를 넣고 읽는 방법에만 관심을 가져야지, 비즈니스적인 의미를 지닌 정보를 설정하는 책임을 지는 것은 바람직 하지 않아 보입니다. 비즈니스 로직을 담당하고 있는 UserSerivce에 add() 메소드를 만들고 이를 통해 User 오브젝트를 받아 처음 가입하는 사용자의 레벨을 BASIC으로 설정하고 DB에 저장하는 로직이 가장 바람직해 보입니다. TDD 방식으로 테스트 코드를 먼저 생성한 후 관련 로직을 만들어 보겠습니다. UserServiceTest, add()@Test public void add() { userDao..