Spring 기본 용어

  • 컨테이너
    • 컨테이너는 인스턴스의 생명주기를 관리한다.
    • 생성된 인스턴스들에게 추가적인 기능을 제공한다.
    • bean은 컨테이너가 관리해주는 인스턴스
  • IoC
    • 라이브러리 - 남이 만든걸 내가 씀
    • 프레임워크 - 내가 만든걸 다른게 쓴다.(스프링이 내 인스턴스를 쓰듯이)
    • ioc : Inversion of Controll 제어의 역전
    • 개발자가 코드 작성 시 그 흐름의 제어를 개발자가 하는게 아니라 프로그램이 하는 것
  • IoC 컨테이너
    • (인터페이스) BeanFactory - 가장 기본적인, 빈의 객체에 대한 생성과 제공 담당, 라이프사이클 관리
    • (인터페이스) ApplicationContext - 스프링이 구현, BeanFactory가 제공하는 모든 기능 제공, 컨테이너 생성시 모든 빈 정보를 메모리에 로딩
    • (인터페이스) WebApplicationContext - 웹환경에서 사용할 때 필요한 기능이 추가된 것
  • DI
    • Dependency Injection 의 약자로 의존성 주입이라는 뜻
  • ApplicationContext (스프링 빈 컨테이너)
    • AnnotationConfigApplicationContext - 하나 이상의 Java Config 클래스에서 스프링애플리케이션 컨텍스트를 로딩
    • ClassPathXmlApplicationContext - 클래스패스에 위치한 XML파일에서 컨텍스트를 로딩
  • Bean의 생명주기
    1. 스프링이 빈을 인스턴스화
    2. 스프링이 값과 빈의 래퍼런스를 빈의 프로퍼티로 주입
    3. 빈이 BaenNameAware를 구현하면 스프링이 빈의 iD를 setBeanName() 메소드에 넘긴다.
    4. 빈이 BeanFactoryAware를 구현하면 setBeanFactory() 메소드를 호출하여 빈 팩토리 전체를 넘긴다.
    5. ApplicationAware - setApplicationContext()메소드 호출, 참조를 넘긴다.
    6. BeanPostProcessor - postProcessBeforInitialization 메소드 호출
    7. InitialzingBean - afterPropertiesSet(), 지정한 초기화 메소드 호출
    8. BeanPostProcessor 구현 - postProcessAfterInirialzation() 메소드 호출
    9. 빈은 어플리케이션에서 사용할 준비가 완료, 애플리케이션 컨텍스트가 소멸될때까지 컨텍스트에 남아있음
    10. 빈은 DisposavleBean인터페이스를 구현하면 스프링은 destroy()메소드 호출
  • AOP
    • 관점지향 프로그래밍, AspectJ, JBossAOP, SpringAOP가 존재
      • 공통적인 부분을 코드밖에서 삽입
      • 포인트컷 - 어떤 부분에서 삽입할지
      • 어드바이스 - 작동될 코드
      • 포인트컷 + 어드바이스
      • 자동으로 코드를 삽입//

빈 설정 방법의 차이


  • XML 기반 설정 방식
    • XML 파일을 사용하는 방법으로 constructor-arg나 property 요소를 사용해 의존성을 주입한다.
  • 자바 기반 설정 방식
    • 자바 클래에서 @Configuration 을 메소드에 @Bean 사용해서 bean을 정의하는 방법
  • 애너테이션 기반 설정 방식
    • @Component 같은 마커 애노테이션이 부여된 클래스를 탐색해서 DI컨테이너에 빈을 자동으로 록하는 방법

XML 방식

xml 문서 (data의 실질적인 표준)
확장가능한 마크업 언어.
- tag이름이 칼럼명 처럼 정해져있지 않다
- 최소 한개의 요소(element)를 가지고 있어야 한다.
요소 = 시작tag(속성을 포함할수있다) + 내용 + 종료 tag
내용이 없을 경우엔 종료tag를 생략 할 수 있다. ex>

xml 문서를 정의하는 방법이 필요(DTD, XML스키마)

xml 문서끼리는 통합할 수 있다. name space를 사용 하여 구분
name space는 보통 uri주소를 사용

Spring xml 파일의 root element는 baens이다.

myBean 인스턴스를 만들어 달라(기본값은 싱글턴)

해당 인스턴스를 bean1 라는 id로 사용하도록 하겠다.
mybean은 기본생성자가 반드시 있어야한다.

  • *Spring은 기본적으로 객체를 싱글턴으로 관리한다.
  • *bean tag하나당 싱글톤 인스턴스가 하나씩 만들어진다.

  • bean을 생성(isntance를 생성) -생성하는 이유는 추가적인 기능등을 스프링에서 관리해주기 위해서
  • 의존성 주입(DI)
  • ApplicationContext를 개발자들은 DI 컨테이너라고 부른다. IoC 컨테이너(공식용어)
    ApplicationContext context
     = new ClassPathXmlApplicationContext("exam01.xml");
    

    ClassPathXmlApplicationContext 인스턴스 생성

MyBean bean1 = (MyBean)context.getBean("bean1");
// MyBean클래스 타입의 빈을 요청한다. 1개일 경우에만 오류가 발생하지 않는다.

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"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="bean1" class="soundsystem.MyBean"/>
    <bean id="bean2" class="soundsystem.MyBean"/>
</beans>

2.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    name property는 setName(..), getName()
    scope이 prototype일 경우에는 매번 인스턴스를 생성한다.
    MyBean bean1 = new MyBean();
    bean1.setName("urstory");
    bean1.setCount(100);
    -->
    <bean id="bean1" class="soundsystem.MyBean">
        <property name="name" value="urstory"/> <!-- 프로퍼티는 게터세터, 보통 세터를 사용   -->
        <property name="count" value="100"/>
    </bean>

    <!-- 파라미터를 2개 받는 생성자를 이용하여 필드를 초기화한다. -->
    <bean id="bean2" class="soundsystem.MyBean">
        <constructor-arg value="urstory"/>
        <constructor-arg value="200"/>
    </bean>

    <bean id="bean3" class="soundsystem.MyBean">
        <constructor-arg>
            <map>
                <!--맵객체에 넣어준다-->
                <entry key="a1" value="Kang"/>
                <entry key="a2" value="Kim"/>
                <entry key="b1" value="Choi"/>
                <entry key="c1" value="Shin"/>
            </map>
        </constructor-arg>
    </bean>
</beans>

3.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="game" class="soundsystem.Game">
        <property name="playerList">
            <!--리스트를 만들어 준다.-->
            <list>
                <ref bean="kim"/>
                <ref bean="choi"/>
                <ref bean="kang"/>
            </list>
        </property>
    </bean>
<!--스프링 컨테이너는 xml 파일의 순서대로 해주는게 아니라 할 수 있는 애들부터 먼저 돌고 다른애들을 만든다.-->
    <!--
    Player kim = new Player();
    kim.setDice(dice); ref = dice의 값이 들어온다 . value = 문자열이 들어온다.
    kim.setName("kim");
    -->
    <bean id="kim" class="soundsystem.Player">
        <property name="dice" ref="dice"/>
        <property name="name" value="kim"/>
    </bean>

    <bean id="choi" class="soundsystem.Player">
        <property name="dice" ref="dice"/>
        <property name="name" value="choi"/>
    </bean>

    <bean id="kang" class="soundsystem.Player">
        <property name="dice" ref="dice"/>
        <property name="name" value="kang"/>
    </bean>



    <!--
Dice dice = new Dice(6);
-->
    <bean id="dice" class="soundsystem.Dice">
        <constructor-arg value="6"/>
    </bean>
</beans>

4.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:c="http://www.springframework.org/schema/c"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="job1" class="soundsystem.Job1"/>
    <bean id="job2" class="soundsystem.Job2"/>
    <bean id="job3" class="soundsystem.Job3"/>
    <!--spring 컨테이너는 인스턴스를 생성 싱글턴으로 생성
           BeanNameAware를 구현해 빈의 id를 setBeanName()메소드를 호출해 빈 객체의 이름을 넘긴다.
           빈 객체가 자기자신의 이름을 알아야 할 경우 사용

           BeanFactoryAware를 구현하면 setBeanFactory()메소드를 호출하여 빈 팩토리 전체를 넘긴다.
           beanFactory는 빈을 등록/생성/조회/반환/관리 기능과 함께 스프링의 각종 부가 서비스를 추가로 제공한다.
           ApplicationContext는 interface이며 BeanFactory를 상속한다.
    -->
    <bean id="jobRunner" class="soundsystem.JobRunner">
        <property name="list">
            <list>
                <!--list인데 문자열을 갖겠다-->
                <value>job1</value>
                <value>job2</value>
                <value>job3</value>
            </list>
        </property>
    </bean>
</beans>

Java 기반 설정


  • 스프링은 아래의 기술을 적극적으로 사용한다. > 아래 기술들은 스프링같은걸 만들고 싶을때 배워서 사용
    • 자바의 리플렉션이란 기술을 이용하면 인터페이스를 구현하는 인스턴스를 동적으로 생성할 수 있다. - 자바 proxy
    • 자바 기본으로 제공하는 기술로는 특정 클래스를 상속받는 인스턴스를 동적으로 생성 할 수 없다. - 오픈소스는 가능 대표적인 프로젝트가 cgilb
      • 동적인 인스턴스는 구현되지않은 인터페이스를 이용해서 클래스없이 만드는것
      • cgilb ~~~처럼 존재하지않는 클래스를 사용해서 만드는것 (바이트코드를 제네릭한다) * 바이트 코드란?
    • 정적 > 디스크에 저장된 / 동적 > 저장되지않은 것으로 생성
    • Spring 이 java config를 읽어 들이면 , 해당 java config클래스를 상속받는 객체를 동적으로 생성한다.
  • *getClass.getName() - 은 인스턴스의 클래스의 이름이 나옴

예제>


// Spring은 @Configuration 붙어있는 클래스를 Java Config로 인식한다.
@Configuration // 자바 config는 꼭 붙어있어야 한다.
public class DiceConfig {
    /*
    빈을 생성하는 메소드에는 @Bean 애노테이션이 붙는다.
    메소드 이름이 id값이 된다.
    <bean id="dice" class="soundsystem.Dice">
        <constructor-arg value="6"/>
    </bean>
     */
    @Bean // 빈은 기본적으로 싱글턴, 자바config에선 오버로딩되면안된다. 메소드명이 id가 되고 id는 유니크해야한다.
    public Dice dice(){ // Spring이 사용하는 cgilb을 이용해 인스턴스가 동적으로 생성되어 한번만 호출된다.
        System.out.println("dice() --------------------------");
        return new Dice(6);
    }

    /*
    스프링 컨테이너가 kim이란 메소드를 호출하는데 파라미터로 Dice객체를 자동으로 넣어준다.
     */
    @Bean
    public Player kim(Dice dice){
        System.out.println("kim()");
        System.out.println(this.getClass().getName());
        Player player = new Player();
        player.setDice(dice);
        player.setName("kim");
        return player;
    }

    @Bean
    public Player kang(Dice dice){
        System.out.println("kang()");
        Player player = new Player();
        player.setDice(dice);
        player.setName("kang");
        return player;
    }

    @Bean
    public Player lee(Dice dice){
        System.out.println("lee()");
        Player player = new Player();
        player.setDice(dice);
        player.setName("lee");
        return player;
    }

    @Bean
    public Game game(Player kim, Player kang, Player lee){// 아이디가 킴, 캉, 리 인 것을 받겠다.
        System.out.println("game");
        Game game = new Game();
        List<Player> list = new ArrayList<>();
        list.add(kim);
        list.add(kang);
        list.add(lee);
        game.setPlayerList(list);
        return game;
    }
}

1.

        ApplicationContext applicationContext
                = new AnnotationConfigApplicationContext(BookConfig.class);
        BookService bookService = applicationContext.getBean(BookService.class);
        bookService.service();
    }

     @ComponentScan
  -@component이 붙은 클래스를 찾아서 인스턴스로 등록한다.
  - soundbook  패키지 이하에서 클래스를 찾는다.
  @controller @restController...

  @bean은 프로구램이 종료될떄 종료되는데 destroymethod = close를 사용하묜 매소드가 끝날때 죽는다.

  스프링에서 데이터 이용
  - DataSource
  - transactionManager 구현
}

2.

@Configuration
@ComponentScan(basePackages = "soundsystem.book")
public class BookConfig {
}

3.

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;

//    public BookService(BookDao bookDao){
//        this.bookDao = bookDao;
//        System.out.println("BookService()");
//    }

    public void service(){
        bookDao.crud();
    }
}
  • hikariCP를 이용한 xml, java기반 설정

XML

  1. applicationContext.xml ~~~ <?xml version=”1.0” encoding=”UTF-8”?>

2. main

public class SpringExam08 { public static void main(String[] args) throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”); DataSource ds = applicationContext.getBean(DataSource.class); try (Connection conn = ds.getConnection()) { System.out.println(“conn is con conconcon”); } catch (Exception ex) { ex.printStackTrace();} } }


Java

1.DataSourceConfig

@Configuration @PropertySource(“classpath:datasource.properties”) public class DataSourceConfig { @Value( “${jdbcUrl}” ) private String jdbcUrl; @Value( “${driverClassName}” ) private String driverClassName; @Value( “${username}” ) private String username; @Value( “${password}” ) private String password;

@Bean
public HikariConfig hikariConfig(){
    HikariConfig hikariConfig = new HikariConfig();
    hikariConfig.setJdbcUrl(jdbcUrl);
    hikariConfig.setDriverClassName(driverClassName);
    hikariConfig.setUsername(username);
    hikariConfig.setPassword(password);
    return hikariConfig;
}

@Bean
public DataSource dataSource(HikariConfig hikariConfig){
    return new HikariDataSource(hikariConfig);
} } ~~~ 2.main ~~~ public class SpringExam09 {

public static void main(String[] args) throws Exception{
    ApplicationContext applicationContext
            = new AnnotationConfigApplicationContext(DataSourceConfig.class);
    DataSource ds = applicationContext.getBean(DataSource.class);
    try(Connection conn = ds.getConnection()){
        System.out.println("conn is ok!");
    }catch(Exception ex){
        ex.printStackTrace();
    }
} } ~~~