프레임워크: 여러 개발자들이 하나의 프로젝트를 작업할 때 어떠한 식으로 작업을 하자라는 개발 방식을 정한 것
자바언어기반으로 응용프로그램을 개발할 때 가장 많이 사용하는 프레임워크!
전자정부프레임워크(정부표준프레임워크)도 스프링 프레임워크 기반으로 만들어진 프레임워크
java application을 보다 쉽고 빠르게 개발할 수 있는 framework.
경량의 컨테이너로써 자바 객체를 직접 관리
객체 생성과 소멸을 개발자가 직접하지않고, 스프링 프레임워크를 통해서 관리하게됨
JAVA 파일에서 JAVA 코드를 줄일 수 있음
반복되는 작업을 줄일 수 있어 기능 개발에 집중할 수 있음
프로젝트 관리가 용이함
다수의 개발자와 동시에 프로젝트 하기가 용이
처음 프로젝트 셋팅이 다소 복잡
개념을 제대로 숙지하지 못하면 코드 분석 조차 하기 힘듦.
preferences -> General -> Appearance -> Colors and Fonts
12이상
인코딩 UTF-8
기존의 사용하던 클래스를 다른 클래스로 변경한다면, 이 클래스를 사용했던 모든 자바 파일을 열어서 해당 파일을 다 변경해야함
자바프로젝트에서 클래스가 변경되면 객체 생성 부분과 참조 변수 선언 부분 모두를 수정해야함.
다형성: 자바에서의 모든 객체는 부모클래스형 참조변수나 구현한 인터페이스 변수에 담을 수 있음,, 이러한 참조변수를 통해 메서드를 호출하면 오버라이딩한 메서드가 호출됨
MainClass.js
import kr.co.softcampus.beans.HelloWorld;
import kr.co.softcampus.beans.HelloWorldEn;
import kr.co.softcampus.beans.HelloWorldKo;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
HelloWorld hello1 = new HelloWorldKo();//new HelloWorldEn();
callMethod(hello1);
HelloWorld hello2 = new HelloWorldKo();//new HelloWorldEn();
callMethod(hello2);
}
public static void callMethod(HelloWorld hello) {
hello.sayHello();
}
}
HelloWorld.java
package kr.co.softcampus.beans;
public interface HelloWorld {
public void sayHello();
}
HelloWorldKo.java
package kr.co.softcampus.beans;
public class HelloWorldKo implements HelloWorld{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("안녕하세요");
}
}
다형성 개념을 사용하면 클래스가 변경되었을 때 참조 변수 선언 부분은 수정하지 않아도 되지만 객체를 생성하는 부분의 코드는 변경되어야 한다.
자바 코드 작성 부분을 줄일 수 있는 효과를 얻을 수 있음
하지만 초기 프로젝트 셋팅이 다소 복잡하므로 충분한 연습이 필요함
스프링 프레임 워크 사용은 xml을 이용하는 방법과 자바 어노테이션을 이용하는 방법 2가지로 구분할 수 있음
자바 프로젝트의 빌드를 자동으로 해주는 도구
개발자가 xml에 작성한 프로젝트 정보를 토대로 컴파일하고 라이브러리를 연결하는 등의 작업을 해주는 도구
Maven 서버를 통해 라이브러리를 다운받아 설정하는 작업도 수행
Build path specifies execution environment JavaSE-1.6. warning. There are no JREs installed in the workspace that are strictly compatible with this environment.
The compiler compliance specified is 1.6 but a JRE 1.8 is used
1) 프로젝트 우클릭 - Properties
2) Project Facets의 Java버전을 1.8
5.19 ver
spring framework
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
추가하기
ctrl a ctrl shift f 누르면 정리하기
version : XML 문서에 사용된 XML의 버전
encoding : XML 문서의 문자셋(character set)을 명시하며, 기본값은 UTF-8
XML 태그는 대소문자를 구분
XML에서 속성값은 반드시 따옴표로 감싸기
띄어쓰기 인식
xmls
해당 위치에 있는 라이브러리를 각각 임의의 변수에 담아서 사용하겠다는 의미
xmls:xsi
인스턴스 네임스페이스 URI를 지정함
xsi:schemaLocation - 두개의 값이 공백으로 구분
첫번째는 사용할 네임스페이스(보통 기본 네임스페이스와 동일)이고,
두번째는 참조할 스키마 파일명
<bean id='hello' class='kr.co.softcampus.beans.HelloWorldEn'/>
HellowWolrdEn을 가지고 객체를 만들겠다
HelloWorld hello1 = (HelloWorld)ctx.getBean("hello");
beans.xml에 있는 id가 hello라고 되어져있는 클래스의 객체를 가지고 와서 반환한다.
HelloWorld -> 형변환할 클래스
이렇게 작성할 수도 있음
HelloWorld hello2 = ctx.getBean("hello", HelloWorld.class);
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.HelloWorld;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
//beans.xml 파일을 로딩한다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
//xml에 정의한 bean 객체의 주소값을 가져온다.
HelloWorld hello1 = (HelloWorld)ctx.getBean("hello");
callMethod(hello1);
HelloWorld hello2 = ctx.getBean("hello", HelloWorld.class);
callMethod(hello2);
ctx.close();
}
public static void callMethod(HelloWorld hello) {
hello.sayHello();
}
}
Id가 hello라고 되어있는 것의 객체를 만들어서 가져와!
만약에 클래스가 변경된다면
<bean id='hello' class='kr.co.softcampus.beans.HelloWorldEn'/>
요부분 한군데만 변경해주면 됨!
ctrl shift / 누르면 주석처리됨!
Programming/Java * Spring
[SpringBoot] No embedded stylesheet instruction for file
.java 파일에서 run을 해주면 됨 ㅇㅇ
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kr.co.softcampus</groupId>
<artifactId>SpringBasic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--xml에서 사용할 속성들 -->
<properties>
<!-- 자바 버전 -->
<java-version>1.8</java-version>
<!-- 스프링 버전 -->
<org.springframework-version>5.1.9.RELEASE</org.springframework-version>
<!-- <org.springframework-version>4.3.25.RELEASE</org.springframework-version> -->
<org.slf4j-version>1.7.26</org.slf4j-version>
<ch.qos.logback-version>1.2.3</ch.qos.logback-version>
</properties>
<!--프로젝트에서 사용할 라이브러리 정보 -->
<dependencies>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- slf4j -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<!-- logback -->
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${ch.qos.logback-version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.HelloWorld;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
//beans.xml 파일을 로딩한다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
//xml에 정의한 bean 객체의 주소값을 가져온다.
HelloWorld hello1 = (HelloWorld)ctx.getBean("hello");
callMethod(hello1);
HelloWorld hello2 = ctx.getBean("hello", HelloWorld.class);
callMethod(hello2);
ctx.close();
}
public static void callMethod(HelloWorld hello) {
hello.sayHello();
}
}
beans.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='hello' class='kr.co.softcampus.beans.HelloWorldEn'/> -->
<bean id='hello' class='kr.co.softcampus.beans.HelloWorldKo'/>
</beans>
HelloWorld.java
package kr.co.softcampus.beans;
public interface HelloWorld {
public void sayHello();
}
HelloWorldEn.java
package kr.co.softcampus.beans;
public class HelloWorldEn implements HelloWorld{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hi~~");
}
}
HelloWorldKo.java
package kr.co.softcampus.beans;
public class HelloWorldKo implements HelloWorld{
@Override
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("안녕하세요");
}
}
IoC ( Inversion of Control) : 제어 역전
일반적으로 프로그래밍을 작성할 때 프로그램이 흘러가는 흐름이나 생성되는 객체에 대한 제어권을 개발자가 가지는 것과 달리 프레임워크가 가지는 것을 의미함
개발자가 코드의 흐름이나 객체 생성에 관련된 코드를 프로그래밍 코드에 직접 작성하는 것이 아닌 프레임워크가 사용하는 파일에 작성하면 이를 토대로 프레임워크가 객체를 생성하여 반환하고 코드가 동작하는 순서를 결정하게 된다는 의미
= java bean
POJO(Plain Old Java Object): 자바 모델이나, 기능, 프레임워크 등에 따르지 않고 홀로 독립적이며 단순한 기능만을 가진 객체들을 의미함
자바에서는 이러한 객체들을 Bean이라고 부른다
POPO(PHP), POCO(닷넷 프레임워크), PODS(C++), POD(Perl) 등
메타데이터: xml이나 java 코드를 가지고 설정한 정보
IoC 컨테이너가 설정해주신 정보를 읽어와가지구 그 정보를 가지고 클래스를 가지고 객체를 만들어서 그 객체를 사용할 수 있도록 반환하는 구조
IoC 컨테이너의 종류
BeanFactory : 클래스를 통해 객체 생성하구 이를 전달함, 객체 간의 관계 형성 및 관리
ApplicationContext: 클래스를 통해 객체 생성하고 이를 전달, 객체 간의 관계 형성 및 관리, 국제화 지원 등 문자열에 관련된 다양한 기능을 제공함
xml bean factory는 xml 데이터 로딩을 하면 기본적으로 정의되어져있는 bean 객체들이 자동으로 생성 노
XmlApplicationContext는 beans.xml에 정의되어져있는 bean 객체들이 자동으로 생성됨 -> 조절 가능
getBean method를 호출할 때 객체 생성 가능 / 자동으로 생성 가능
MainClass.java
package kr.co.softcampus.main;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
//test1();
//test2();
test3();
}
// BeanFactory - 패키지 내부
public static void test1() {
ClassPathResource res = new ClassPathResource("kr/co/softcampus/config/beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
TestBean t1 = factory.getBean("t1", TestBean.class);
System.out.printf("t1 : %s\n", t1);
TestBean t2 = factory.getBean("t1", TestBean.class);
System.out.printf("t2 : %s\n", t2);
}
// BeanFactory - 패키지 외부
public static void test2() {
FileSystemResource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
TestBean t1 = factory.getBean("t2", TestBean.class);
System.out.printf("t1: %s\n", t1);
TestBean t2 = factory.getBean("t2", TestBean.class);
System.out.printf("t2: %s\n", t2);
}
//ApplicationContext - 패키지 내부
public static void test3() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean t1 = ctx.getBean("t1", TestBean.class);
System.out.printf("t1: %s\n", t1);
TestBean t2 = ctx.getBean("t1", TestBean.class);
System.out.printf("t2: %s\n", t2);
ctx.close();
}
//ApplicationContext - 패키지 외부
public static void test4() {
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("beans.xml");
TestBean t1 = ctx.getBean("t2", TestBean.class);
System.out.printf("t1: %s\n", t1);
TestBean t2 = ctx.getBean("t2", TestBean.class);
System.out.printf("t2: %s\n", t2);
ctx.close();
}
}
빈: 스프링 IoC 컨테이너가 관리하는 객체
Spring에는 사용할 Bean 객체를 bean configuration file에 정의를 하고 필요할 때 객체를 가져와 사용하는 방법을 이용
bean tag: 사용할 bean을 정의하는 태그
class: 객체를 생성하기 위해 사용할 클래스를 지정
-> 반드시 작성해야하는 속성
id: Bean 객체를 가져오기 위해 사용하는 이름을 지정
lazy-init: 싱글톤인 경우 xml을 로딩할 때 객체 생성 여부를 설정
true: xml 로딩 시 객체를 생성하지 않고 객체를 가져올 때 생성함
scope: 객체의 범위 설정
singleton: 객체를 하나만 생성해서 사용
prototype: 객체를 가져올 때 마다 객체 생성
pom.xml 붙여넣기하구 -> 버전 확인
config package만들고 beans.xml 넣어주기
main package 만들기 -> main class 만들기
beans package 만들기 -> class 만들기
beans.xml
<!-- xml을 로딩할 때 자동으로 객체가 생성됨 -->
<!-- 현재까지의 학습 진도상 id 속성이 없다면 객체의 주소값을 받아서 사용할 수 없다. -->
<bean class='kr.co.softcampus.beans.TestBean'/>
<!-- xml을 로딩할 때 자동으로 객체가 생성됨 -->
<!--id 속성에 이름을 부여하면 getBean 메서드를 통해 객체의 주소값을 받아 사용할 수 있음 -->
<!-- 생성된 객체는 더이상 생성되지않는다. Singleton -->
<bean id='test1' class='kr.co.softcampus.beans.TestBean'/>
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
//id가 test1인 bean 객체의 주소값을 받아온다.
TestBean t1 = ctx.getBean("test1",TestBean.class);
System.out.printf("t1 : %s\n", t1);
TestBean t2 = ctx.getBean("test1",TestBean.class);
System.out.printf("t2 : %s\n", t2);
ctx.close();
}
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
public TestBean() {
System.out.println("TestBean의 생성자");
}
}
결과
TestBean의 생성자
TestBean의 생성자
t1 : kr.co.softcampus.beans.TestBean@163e4e87
t2 : kr.co.softcampus.beans.TestBean@163e4e87
lazy-init="true"를 설정하면 xml을 로딩할 때 객체 생성하지않음
getbean 메서드 호출할 때 그 때 생성됨
<!-- lazy-init:true - xml을 로딩할 때 객체가 생성되지않음. (생략하면 false)-->
<!-- getBean 메서드를 호출할 때 객체가 생성되며 singleton이기 때문에 객체는 하나만 생성됨 -->
<bean id = 'test2' class='kr.co.softcampus.beans.TestBean' lazy-init="true"/>
MainClass.java
// id가 test2인 bean 객체의 주소값을 받아온다.
TestBean t3 = ctx.getBean("test2", TestBean.class);
System.out.printf("t3 : %s\n", t3);
TestBean t4 = ctx.getBean("test2", TestBean.class);
System.out.printf("t4 : %s\n", t4);
결과
TestBean의 생성자
t3 : kr.co.softcampus.beans.TestBean@56de5251
t4 : kr.co.softcampus.beans.TestBean@56de5251
scope:prototype - xml을 로딩할 때 객체가 생성되지않음
getbean 메서드 호출할 때마다 객체 생성해서 반환
beans.xml
<!-- scope:prototype - xml을 로딩할 때 객체가 생성되지않음.-->
<!-- getBean 메서드를 호출할 때마다 새로운 객체를 생성해서 반환.-->
<bean id='test3' class='kr.co.softcampus.beans.TestBean' scope='prototype'/>
MainClass.java
// id가 test3인 bean 객체의 주소값을 받아온다.
TestBean t5 = ctx.getBean("test3", TestBean.class);
System.out.printf("t5: %s\n", t5);
TestBean t6 = ctx.getBean("test3", TestBean.class);
System.out.printf("t6: %s\n", t6);
결과
TestBean의 생성자
t5: kr.co.softcampus.beans.TestBean@419c5f1a
TestBean의 생성자
t6: kr.co.softcampus.beans.TestBean@12b0404f
getBean 메서드 호출할 때마다 객체 생성됨을 확인할 수 있음
전체 프로그램에서 객체를 하나만 만들어서 그 객체를 계속 쓰겠다하면! 싱글톤으로!
싱글톤으로 쓸건데 내가 필요할 때 객체를 생성하겠다! 하면 lazy-init:true
같은 클래스를 가지고 내가 원하는만큼 객체들을 만들어 쓰겠다고하면 prototype으로!
IoC 컨테이너 종료 때 객체 소멸됨
객체가 생성되면 가장 먼저 생성자가 호출된다.
init-method: 생성자 호출 이후 자동으로 호출된다.
destroy-method: 객체가 소멸될 때 자동으로 호출된다.
default-init-method: init-method를 설정하지 않은 경우 자동으로 호출된다.
default-destroy-method: destroy-method를 설정하지 않은 경우 자동으로 호출된다.
모든 빈들이 객체가 생성되거나 소멸될 때 자동으로 호출되는 메소드의 이름이 동일하다 하면, default-init-method와 default-destroy-method를 등록하면 됨!
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자입니다");
}
public void bean1_init() {
System.out.println("TestBean의 init 메서드");
}
public void bean1_destroy() {
System.out.println("TestBean의 destory 메서드");
}
}
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
public TestBean2() {
System.out.println("TestBean2의 생성자");
}
public void default_init() {
System.out.println("TestBean2의 default_init");
}
public void default_destroy() {
System.out.println("TestBean2의 default_destroy");
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.beans.TestBean2;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 t1 = ctx.getBean("t1", TestBean1.class);
System.out.printf("t1:%s\n", t1);
System.out.println("-------------------------");
TestBean2 t2 = ctx.getBean("t2", TestBean2.class);
System.out.printf("t2:%s\n", t2);
System.out.println("-------------------------");
ctx.close();
}
}
beans.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"
default-init-method="default_init" default-destroy-method="default_destroy">
<bean id='t1' class='kr.co.softcampus.beans.TestBean1' lazy-init='true' init-method='bean1_init' destroy-method="bean1_destroy"/>
<bean id='t2' class='kr.co.softcampus.beans.TestBean2' lazy-init='true' />
</beans>
결과
17:24:59.389 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@50cbc42f
17:24:59.944 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 2 bean definitions from class path resource [kr/co/softcampus/config/beans.xml]
17:25:00.112 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 't1'
TestBean1의 생성자입니다
TestBean의 init 메서드t1:kr.co.softcampus.beans.TestBean1@647fd8ce
17:25:00.157 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 't2'
TestBean2의 생성자
TestBean2의 default_initt2:kr.co.softcampus.beans.TestBean2@5dd6264
17:25:00.180 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@50cbc42f, started on Wed Dec 21 17:24:59 KST 2022
TestBean2의 default_destroy
TestBean의 destory 메서드
전체적인거 보다 자기자신에게 있는거 먼저
TestBean3.java
package kr.co.softcampus.beans;
public class TestBean3 {
public TestBean3() {
System.out.println("TestBean3의 생성자");
}
public void default_init() {
System.out.println("TestBean3의 default_init");
}
public void default_destroy() {
System.out.println("TestBean3의 default_destroy");
}
public void bean3_init() {
System.out.println("TestBean3의 init 메서드");
}
public void bean3_destroy() {
System.out.println("TestBean3의 destory 메서드");
}
}
beans.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"
default-init-method="default_init" default-destroy-method="default_destroy">
<!-- 객체가 생성될 때 생성자가 호출된 이후 init-method에 설정한 메서드가 자동으로 호출되고 IoC 컨테이너의 close 메서드를 호출하면
객체가 소멸되며 destory-method의 설정한 메서드가 자동으로 호출된다. -->
<bean id='t1' class='kr.co.softcampus.beans.TestBean1' lazy-init='true' init-method='bean1_init' destroy-method="bean1_destroy"/>
<!-- init-method와 destroy-method가 설정되어 있지 않다면 default-init-method와 default-destroy-method에 설정되어 있는 메서드를 호출한다. -->
<bean id='t2' class='kr.co.softcampus.beans.TestBean2' lazy-init='true' />
<!-- 만약 init-method, destroy-method와 default-init-method, default-destroy-method에 등록되어 있는 메서드가 모두 있을 경우 init-method, destroy-method에 설정되어 있는 메소드가 호출된다. -->
<bean id='t3' class='kr.co.softcampus.beans.TestBean3' lazy-init='true' init-method='bean3_init' destroy-method="bean3_destroy"/>
</beans>
결과
(생략)
17:39:08.115 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 't3'
TestBean3의 생성자
TestBean3의 init 메서드t3:kr.co.softcampus.beans.TestBean3@48fa0f47
17:39:08.136 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@50cbc42f, started on Wed Dec 21 17:39:07 KST 2022
TestBean3의 destory 메서드
TestBean2의 default_destroy
TestBean의 destory 메서드
<!-- default-init-method, default-destroy-method: 설정한 메서드가 존재하지 않으면 무시된다.
init-method, destroy-method: 설정한 메서드가 없으면 오류가 발생한다. -->
<bean id='t4' class='kr.co.softcampus.beans.TestBean4'
lazy-init='true' init-method='bean4_init'
destroy-method="bean4_destroy" />
객체가 생성될 때 생성자가 호출된 이후 init-method에 설정한 메서드가 자동으로 호출되고 IoC 컨테이너의 close 메서드를 호출하면 객체가 소멸되며 destory-method의 설정한 메서드가 자동으로 호출된다.
init-method와 destroy-method가 설정되어 있지 않다면 default-init-method와 default-destroy-method에 설정되어 있는 메서드를 호출한다.
만약 init-method, destroy-method와 default-init-method, default-destroy-method에 등록되어 있는 메서드가 모두 있을 경우 init-method, destroy-method에 설정되어 있는 메소드가 호출된다.
default-init-method, default-destroy-method: 설정한 메서드가 존재하지 않으면 무시된다.
init-method, destroy-method: 설정한 메서드가 없으면 오류가 발생
Bean 객체를 정의할 때 init-method 속성을 설정하면 객체가 생성될 때 자동으로 호출될 메서드를 지정할 수 있다
이 때 BeanPostProcessor 인터페이스를 구현한 클래스를 정의하면 Bean 객체를 생성할 때 호추될 init 메서드 호출을 가로채 다른 메서드를 호출할 수 있도록 할 수 있음
postProcessBeforeInitialization: init-method에 지정된 메서드가 호출되기 전에 호출된다.
postProcessAfterInitialization: init-method에 지정된 메서드가 호출된 후에 호출된다.
init-method가 지정되어 있지 않더라도 자동으로 호출된다.
Spring에서는 객체가 생성될 때 init-method로 지정된 메서드가 호추되기 전, 후에 다른 메서드를 호추할 수 있도록 지원하고 있다.
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.beans.TestBean2;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 t1 = ctx.getBean("t1", TestBean1.class);
System.out.printf("t1 : %s\n", t1);
System.out.println("----------------------");
TestBean2 t2 = ctx.getBean("t2", TestBean2.class);
System.out.printf("t2: %s\n", t2);
ctx.close();
}
}
TestBeanPostProcessor.java
package kr.co.softcampus.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class TestBeanPostProcessor implements BeanPostProcessor{
//init-method 호출 전
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("before");
switch(beanName) {
case "t1":
System.out.println("id가 t1인 bean 객체 생성");
break;
case "t2":
System.out.println("id가 t2인 bean 객체 생성");
break;
}
return bean;
}
//init-method 호출후
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("after");
return bean;
}
}
beans.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='t1' class='kr.co.softcampus.beans.TestBean1' lazy-init='true' init-method='bean1_init'/>
<bean id='t2' class='kr.co.softcampus.beans.TestBean2' lazy-init='true' init-method='bean2_init'/>
<bean class="kr.co.softcampus.processor.TestBeanPostProcessor"/>
</beans>
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자");
}
public void bean1_init() {
System.out.println("TestBean1의 init 메서드");
}
}
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
public TestBean2() {
System.out.println("TestBean2의 생성자");
}
public void bean2_init() {
System.out.println("TestBean2의 init 메서드");
}
}
결과
TestBean1의 생성자
before
id가 t1인 bean 객체 생성
TestBean1의 init 메서드
aftert1: kr.co.softcampus.beans.TestBean1@56de5251
TestBean2의 생성자
before
id가 t2인 bean 객체 생성
TestBean2의 init 메서드
after
t2: kr.co.softcampus.beans.TestBean2@419c5f1a
의존성 주입은 Spring에서 아주 중요한 개념이자 장점
Bean 객체를 생성할 때 Bean 객체가 관리할 값이나 객체를 주입하는 것을 의미
Bean 객체 생성 후 Bean 객체가 가질 기본 값을 자바 코드로 설정하는 것이 아닌 Bean을 정의하는 xml 코드에서 정의하는 개념
Bean을 정의할 때 constructor-arg 태그를 이용해 주입하게 되면 생성자를 통해 주입할 수 있음
value: 기본 자료형 값과 문자열 값을 설정
ref: 객체 설정
type: 저장할 값의 타입 설정
index: 지정된 값을 주입할 생성자의 매개변수 인덱스 번호
spring에서 값을 주입하면 문자열 > double > int 이런 순서
beans.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='obj1' class='kr.co.softcampus.beans.TestBean' lazy-init='true'/>
<bean id='obj2' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='100'/>
</bean>
<bean id='obj3' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='11.11'/>
</bean>
<bean id='obj4' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='문자열'/>
</bean>
</beans>
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
private int data1;
private double data2;
private String data3;
public TestBean() {
System.out.println("TestBean의 기본 생성자");
this.data1=0;
this.data2=0.0;
this.data3=null;
}
public TestBean(int data1) {
System.out.println("TestBean의 생성자: int 변수 1개");
this.data1 = data1;
this.data2 = 0.0;
this.data3 = null;
}
public TestBean(double data2) {
System.out.println("TestBean의 생성자: double 변수 1개 ");
this.data1=0;
this.data2=data2;
this.data3=null;
}
public TestBean(String data) {
System.out.println("TestBean의 생성자: String 변수 1개");
this.data1 = 0;
this.data2 = 0.0;
this.data3 = data3;
}
public void printData() {
System.out.printf("data1 : %d\n",data1);
System.out.printf("data2 : %f\n", data2);
System.out.printf("data3 : %s\n", data3);
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean t1 = new TestBean();
t1.printData();
System.out.println("--------------------");
TestBean t2 = new TestBean(100);
t2.printData();
System.out.println("--------------------");
TestBean t3 = new TestBean(11.11);
t3.printData();
System.out.println("--------------------");
TestBean t4 = new TestBean("문자열");
t4.printData();
TestBean obj1 = ctx.getBean("obj1", TestBean.class);
obj1.printData();
System.out.println("--------------------");
TestBean obj2 = ctx.getBean("obj2", TestBean.class);
obj2.printData();
System.out.println("--------------------");
TestBean obj3 = ctx.getBean("obj3", TestBean.class);
obj3.printData();
System.out.println("--------------------");
TestBean obj4 = ctx.getBean("obj4", TestBean.class);
obj4.printData();
ctx.close();
}
}
물론 이렇게 type 지정 가능
<bean id='obj3' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='11.11' type='double'/>
</bean>
만들어져있는 매개변수의 순서와 어긋나게 만듦
그런데 오류가 나지않음
먼저 순서대로 값을 주입할 수 있는 생성자를 찾음
만약에 그 생성자가 없다고 하면, 이 값들을 모두 다 주입할 수 있는 생성자를 찾음 ( 값과 상관 ㄴ)
TestBean.java
public TestBean(int data1, double data2, String data3) {
System.out.println("TestBean의 생성자 : 변수 3개");
this.data1=data1;
this.data2=data2;
this.data3=data3;
}
beans.xml
<bean id='obj6' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='반갑습니다' type='java.lang.String' />
<constructor-arg value='300' type='int' />
<constructor-arg value='33.33' type='double' />
</bean>
MainClass.java
TestBean obj6 = ctx.getBean("obj6", TestBean.class);
obj6.printData();
기왕이면 생성자의 순서대로~
동일 type 변수 여러개 있을 경우 index 맞춰주면 굿
beans.xml
<bean id='obj7' class='kr.co.softcampus.beans.TestBean' lazy-init='true'>
<constructor-arg value='44.44' type='double' index='1'/>
<constructor-arg value='44' type='int' index='0'/>
<constructor-arg value='안녕하세요' type='java.lang.String' index='2' />
</bean>
결과
TestBean의 생성자 : 변수 3개
data1 : 44
data2 : 44.440000
data3 : 안녕하세요
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
private DataBean data1;
private DataBean data2;
public TestBean2(DataBean data1, DataBean data2) {
this.data1=data1;
this.data2=data2;
}
public void printData() {
System.out.printf("data1: %s\n", data1);
System.out.printf("data2: %s\n", data2);
}
}
1) java로
DataBean d1 = new DataBean();
DataBean d2 = new DataBean();
TestBean2 t200 = new TestBean2(d1,d2);
t200.printData();
결과
data1: kr.co.softcampus.beans.DataBean@50eac852
data2: kr.co.softcampus.beans.DataBean@16ec5519
2) xml
<bean id='obj8' class='kr.co.softcampus.beans.TestBean2' lazy-init='true'>
<constructor-arg>
<bean class='kr.co.softcampus.beans.DataBean'/>
</constructor-arg>
<constructor-arg>
<bean class='kr.co.softcampus.beans.DataBean'/>
</constructor-arg>
</bean>
각각 객체가 들어감
main
TestBean2 obj8 = ctx.getBean("obj8", TestBean2.class);
obj8.printData();
결과
data1: kr.co.softcampus.beans.DataBean@3835c46
data2: kr.co.softcampus.beans.DataBean@1dde4cb2
이미 정의되어있는 빈을 주입하고 싶다면??
<bean id='data_bean' class='kr.co.softcampus.beans.DataBean' scope='prototype'/>
<bean id='obj9' class='kr.co.softcampus.beans.TestBean2' lazy-init='true'>
<constructor-arg ref='data_bean'/>
<constructor-arg ref='data_bean'/>
</bean>
Bean 객체를 생성할 때 객체의 기본 값을 생성자를 통해 주입할 수 있음
source -> generate getters and setters
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
private int data1;
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
TestBean obj1 = new TestBean();
obj1.setData1(100);
System.out.printf("obj.data1 : %d\n", obj1.getData1());
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean t1 = ctx.getBean("t1", TestBean.class);
ctx.close();
}
}
beans.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='t1' class='kr.co.softcampus.beans.TestBean'>
</bean>
</beans>
2)beans.xml 정의해서 사용하기
beans.xml
<bean id='t1' class='kr.co.softcampus.beans.TestBean'>
<property name='data1' value='100'/>
<property name='data2' value='11.11'/>
<property name='data3' value='true'/>
<property name='data4' value='안녕하세요'/>
</bean>
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
private int data1;
private double data2;
private boolean data3;
private String data4;
public double getData2() {
return data2;
}
public void setData2(double data2) {
this.data2 = data2;
}
public boolean isData3() {
return data3;
}
public void setData3(boolean data3) {
this.data3 = data3;
}
public String getData4() {
return data4;
}
public void setData4(String data4) {
this.data4 = data4;
}
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
TestBean obj1 = new TestBean();
obj1.setData1(100);
System.out.printf("obj.data1 : %d\n", obj1.getData1());
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean t1 = ctx.getBean("t1", TestBean.class);
System.out.printf("t1.data1 : %d\n", t1.getData1());
System.out.printf("t1.data2 : %f\n", t1.getData2());
System.out.printf("t1.data3 : %s\n", t1.isData3());
System.out.printf("t1.data4 : %s\n", t1.getData4());
ctx.close();
}
}
3) 객체 주입
<property name='data5'>
<bean class='kr.co.softcampus.beans.DataBean'/>
</property>
DataBean 클래스를 가지고 객체를 만들어서 data5에 주입
<property name='data6' ref='data_bean'/>
</bean>
<bean id='data_bean' class='kr.co.softcampus.beans.DataBean'/>
이미 정의된 bean을 주입할 때는 ref이용
data_bean이라는 아이디를 가지고 있는 bean 객체의 주소값을 data6에 주입
bean을 정의할 때 주입해야 하는 멤버가 컬렉션인 경우 컬렉션이 관리할 객체를 초기에 설정할 수 있음
여기에는 list, map, set, property를 사용하도록 함
1) list
MainClass.java
package kr.co.softcampus.main;
import java.util.List;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean t1 = ctx.getBean("t1",TestBean.class);
List<String> list1 = t1.getList1();
for(String str:list1) {
System.out.printf("list1 : %s\n", str);
}
ctx.close();
}
}
TestBean.java
package kr.co.softcampus.beans;
import java.util.List;
public class TestBean {
private List<String> list1;
public List<String> getList1() {
return list1;
}
public void setList1(List<String> list1) {
this.list1 = list1;
}
}
beans.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='t1' class='kr.co.softcampus.beans.TestBean'>
<!-- 제네릭이 String인 List -->
<property name='list1'>
<list>
<value>문자열1</value>
<value>문자열2</value>
<value>문자열3</value>
</list>
</property>
</bean>
</beans>
2) List
MainClass.java
List<Integer> list2 = t1.getList2();
for(int value : list2) {
System.out.printf("list2 : %d\n",value);
}
TestBean.java
private List<Integer> list2;
public List<Integer> getList2() {
return list2;
}
public void setList2(List<Integer> list2) {
this.list2 = list2;
}
beans.xml
<!-- 제네릭이 Integer인 List -->
<property name='list2'>
<list>
<value type='int'>100</value>
<value type='int'>200</value>
<value type='int'>300</value>
</list>
</property>
type 정해주는게 조음
3) 객체주입
beans.xml
<!-- 제네릭이 DataBean인 List -->
<property name='list3'>
<list>
<bean class='kr.co.softcampus.beans.DataBean'/>
<bean class='kr.co.softcampus.beans.DataBean'/>
</list>
</property>
TestBean.java
private List<DataBean> list3;
public List<DataBean> getList3() {
return list3;
}
public void setList3(List<DataBean> list3) {
this.list3 = list3;
}
MainClass.java
List<DataBean> list3 = t1.getList3();
for(DataBean obj : list3) {
System.out.printf("list3 : %s\n", obj);
}
이런식으로도 가능
<!-- 제네릭이 DataBean인 List -->
<property name='list3'>
<list>
<bean class='kr.co.softcampus.beans.DataBean'/>
<bean class='kr.co.softcampus.beans.DataBean'/>
<ref bean='data_bean'/>
<ref bean='data_bean'/>
</list>
</property>
<bean id='data_bean' class='kr.co.softcampus.beans.DataBean' scope='prototype'/>
TestBean.java
private Set<String> set1;
private Set<Integer> set2;
private Set<DataBean> set3;
public Set<String> getSet1() {
return set1;
}
public void setSet1(Set<String> set1) {
this.set1 = set1;
}
public Set<Integer> getSet2() {
return set2;
}
public void setSet2(Set<Integer> set2) {
this.set2 = set2;
}
public Set<DataBean> getSet3() {
return set3;
}
public void setSet3(Set<DataBean> set3) {
this.set3 = set3;
}
MainClass.java
Set<String> set1 = t1.getSet1();
Set<Integer> set2 = t1.getSet2();
Set<DataBean> set3 = t1.getSet3();
for(String str:set1) {
System.out.printf("set1 : %s\n", str);
}
for(int value : set2) {
System.out.printf("set2 : %d\n",value);
}
for(DataBean obj : set3) {
System.out.printf("set3 : %s\n", obj);
}
beans.xml
<!-- 제네릭이 String인 set -->
<property name='set1'>
<set>
<value>문자열1</value>
<value>문자열2</value>
<value>문자열3</value>
</set>
</property>
<!-- 제네릭이 Integer인 set -->
<property name='set2'>
<set>
<value type='int'>100</value>
<value type='int'>200</value>
<value type='int'>300</value>
</set>
</property>
<!-- 제네릭이 DataBean인 List -->
<property name='set3'>
<set>
<bean class='kr.co.softcampus.beans.DataBean'/>
<bean class='kr.co.softcampus.beans.DataBean'/>
<ref bean='data_bean'/>
<ref bean='data_bean'/>
</set>
</property>
</bean>
<bean id='data_bean' class='kr.co.softcampus.beans.DataBean' scope='prototype'/>
결과
set1 : 문자열1
set1 : 문자열2
set1 : 문자열3
set2 : 100
set2 : 200
set2 : 300
set3 : kr.co.softcampus.beans.DataBean@72d1ad2e
set3 : kr.co.softcampus.beans.DataBean@2d7275fc
set3 : kr.co.softcampus.beans.DataBean@399f45b1
왜 마지막에 하나만 출력?
Spring을 통해서 set에 객체를 주입할 때, id가 똑같은 bean을 주입하면 하나만 주입됨. prototype이라 엄연히 주소값은 새롭게 만들어지는데 그거와 상관없이 id가 똑같은 bean을 두 개 이상 주입 못함,,,
똑같은 class type의 bean을 무수히 많이 주입해야겠다고하면 bean 태그 이용해서하기
Map 같은 경우는 type에 관계없이 매개체 하나하나에 대한 정보 저장
Object는 모든 클래스 type의 객체 주소값을 받을 수 있음
TestBean.java
private Map<String, Object> map1;
public Map<String, Object> getMap1() {
return map1;
}
public void setMap1(Map<String, Object> map1) {
this.map1 = map1;
}
MainClass.java
Map<String, Object> map1 = t1.getMap1();
String a1 = (String)map1.get("a1");
int a2 = (Integer)map1.get("a2");
DataBean a3 = (DataBean)map1.get("a3");
DataBean a4 = (DataBean)map1.get("a4");
List<String> a5 = (List<String>)map1.get("a5");
System.out.printf("a1: %s\n", a1);
System.out.printf("a2: %d\n", a2);
System.out.printf("a3: %s\n", a3);
System.out.printf("a4: %s\n", a4);
for(String str: a5) {
System.out.printf("a5 : %s\n", str);
}
beans.xml
<!-- map -->
<property name="map1">
<map>
<entry key='a1' value='문자열'/>
<entry key='a2' value='100' value-type='int'/>
<entry key ='a3'>
<bean class='kr.co.softcampus.beans.DataBean'/>
</entry>
<entry key='a4' value-ref="data_bean"/>
<entry key='a5'>
<list>
<value>문자열1</value>
<value>문자열2</value>
<value>문자열3</value>
</list>
</entry>
</map>
</property>
</bean>
map안에 list 받기도 가능
문자열만 저장하여 사용
TestBean.java
private Properties prop1;
public Properties getProp1() {
return prop1;
}
public void setProp1(Properties prop1) {
this.prop1 = prop1;
}
beans.xml
<!-- property -->
<property name='prop1'>
<props>
<prop key="p1">문자열1</prop>
<prop key="p2">문자열2</prop>
<prop key="p3">문자열3</prop>
</props>
</property>
MainClass.java
Properties prop1 = t1.getProp1();
String p1 = prop1.getProperty("p1");
String p2 = prop1.getProperty("p2");
String p3 = prop1.getProperty("p3");
System.out.printf("p1 : %s\n", p1);
System.out.printf("p2 : %s\n", p2);
System.out.printf("p3 : %s\n", p3);
결과
p1 : 문자열1
p2 : 문자열2
p3 : 문자열3
Bean 객체를 생성할 때 주입할 멤버가 컬렉션이라면 컬렉션이 관리할 객체를 주입할 수 있다.
bean을 정의할 때 주입할 객체는 생성자를 통한 주입이나 setter를 통한 주입을 사용
spring에서는 객체를 주입할 때 (참조 변수 경우) 자동으로 주입될 수 있도록 설정할 수 있음
자동 주입은 이름, 타입, 생성자를 통할 수 있으며 auto wire라는 용어로 부름
byName : 빈 객체의 프로퍼티 이름과 정의된 빈의 이름이 같은 것을 찾아 자동으로 주입한다.
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
private DataBean1 data1;
private DataBean1 data2;
public DataBean1 getData1() {
return data1;
}
public void setData1(DataBean1 data1) {
this.data1 = data1;
}
public DataBean1 getData2() {
return data2;
}
public void setData2(DataBean1 data2) {
this.data2 = data2;
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
//beans.xml 파일을 로딩한다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 obj = ctx.getBean("obj1", TestBean1.class);
System.out.printf("obj1.data1 : %s\n", obj.getData1());
System.out.printf("obj1.data2 : %s\n", obj.getData2());
System.out.println("-----------------------------");
TestBean1 obj2 = ctx.getBean("obj2", TestBean1.class);
System.out.printf("obj2.data1 : %s\n", obj2.getData1());
System.out.printf("obj2.data2 : %s\n", obj2.getData2());
ctx.close();
}
}
beans.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='obj1' class='kr.co.softcampus.beans.TestBean1'>
<property name="data1" ref="data_bean1"/>
<property name="data2" ref="data_bean1"/>
</bean>
<bean id='data_bean1' class='kr.co.softcampus.beans.DataBean1' scope='prototype'/>
<bean id='obj2' class='kr.co.softcampus.beans.TestBean1' autowire='byName'/>
<bean id='data1' class='kr.co.softcampus.beans.DataBean1'/>
<bean id='data2' class='kr.co.softcampus.beans.DataBean1'/>
</beans>
결과
obj1.data1 : kr.co.softcampus.beans.DataBean1@3bb9a3ff
obj1.data2 : kr.co.softcampus.beans.DataBean1@661972b0
obj2.data1 : kr.co.softcampus.beans.DataBean1@5af3afd9
obj2.data2 : kr.co.softcampus.beans.DataBean1@323b36e0
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
private DataBean2 data1;
private DataBean2 data2;
public DataBean2 getData1() {
return data1;
}
public void setData1(DataBean2 data1) {
this.data1 = data1;
}
public DataBean2 getData2() {
return data2;
}
public void setData2(DataBean2 data2) {
this.data2 = data2;
}
}
MainClass.java
TestBean2 obj3 = ctx.getBean("obj3", TestBean2.class);
System.out.printf("obj3.data1 : %s\n", obj3.getData1());
System.out.printf("obj3.data2 : %s\n", obj3.getData2());
타입이기에 id를 따로 설정할 필요 X
beans.xml
<bean id='obj3' class='kr.co.softcampus.beans.TestBean2' autowire="byType"/>
<bean class='kr.co.softcampus.beans.DataBean2'/>
MainClass.java
TestBean2 obj3 = ctx.getBean("obj3", TestBean2.class);
System.out.printf("obj3.data1 : %s\n", obj3.getData1());
System.out.printf("obj3.data2 : %s\n", obj3.getData2());
결과
obj3.data1 : kr.co.softcampus.beans.DataBean2@4fb0f2b9
obj3.data2 : kr.co.softcampus.beans.DataBean2@4fb0f2b9
만약 하나 더 쓰면
<bean class='kr.co.softcampus.beans.DataBean2'/>
<bean class='kr.co.softcampus.beans.DataBean2'/>
동일한 타입이 2개이상이면 오류
Constructor: 생성자의 매개 변수 타입과 정의된 bean의 타입이 일치할 경우 주입됨
이 때, 동일 타입의 빈이 두 개 이상 정의되어 있으면 오류발생
TestBean3.java
public TestBean3(DataBean2 data3, DataBean2 data4) {
this.data3 = data3;
this.data4 = data4;
}
beans.xml
<!-- 생성자 -->
<bean id='obj4' class='kr.co.softcampus.beans.TestBean3'>
<constructor-arg ref="data_bean2" index="0"/>
<constructor-arg ref="data_bean2" index="1"/>
</bean>
<!-- 생성자 자동주입 -->
<bean id='obj5' class='kr.co.softcampus.beans.TestBean3' autowire="constructor"/>
MainClass.java
TestBean3 obj5 = ctx.getBean("obj5", TestBean3.class);
System.out.printf("obj5.data1 : %s\n", obj5.getData1());
System.out.printf("obj5.data2 : %s\n", obj5.getData2());
System.out.printf("obj5.data3 : %s\n", obj5.getData3());
System.out.printf("obj5.data4 : %s\n", obj5.getData4());
beans.xml
<!-- 문자열 생성자 주입 -->
<bean id='obj6' class='kr.co.softcampus.beans.TestBean3'>
<constructor-arg value='100' index='0' type='int'/>
<constructor-arg value='문자열' index='1'/>
<constructor-arg ref='data_bean2' index='2'/>
<constructor-arg ref='data_bean2' index='3'/>
</bean>
<!-- 문자열 생성자 자동 주입 -->
<bean id='obj7' class='kr.co.softcampus.beans.TestBean3' autowire="constructor">
<constructor-arg value='200' index='0' type='int'/>
<constructor-arg value='문자열2' index='1'/>
</bean>
자동주입은 문자열이랑 정수값은 주입 ㄴ 객체 주소값만 O
참조변수 제외한 나머지들은 직접 제시해야함
결과
obj7.data1 : 200
obj7.data2 : 문자열2
obj7.data3 : kr.co.softcampus.beans.DataBean2@73a1e9a9
obj7.data4 : kr.co.softcampus.beans.DataBean2@73a1e9a9
default-autowire="byName">
<bean id='obj8' class='kr.co.softcampus.beans.TestBean1'/>
결과
obj8.data1 : kr.co.softcampus.beans.DataBean1@7b98f307
obj8.data2 : kr.co.softcampus.beans.DataBean1@4802796d
<!-- 아무것도 자동 주입 ㄴ -->
<bean id='obj9' class='kr.co.softcampus.beans.TestBean1' autowire="no"/>
결과
obj9.data1 : null
obj9.data2 : null
xml과 java파일의 차이는 xml은 값을 정해줘야 하는 반면 java 파일은 코드를 자유롭게 작성할 수 있다는 것
//xml을 사용하는 방식
ClassPathXmlApplicationContext ctx1 = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
ctx1.close();
System.out.println("=========================");
//java 파일을 사용하는 방식
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
ctx2.close();
@ Bean annotation은 bean 객체를 정의할 때 사용
메서드의 이름이 bean의 이름이 됨
@ Bean(name=이름) : bean의 이름을 새롭게 정의
@ Lazy : lazy-init 속성 지정
@ Scope : bean의 scope를 설정
@ Primary: primay 속성 지정
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import kr.co.softcampus.beans.TestBean1;
@Configuration
public class BeanConfigClass {
// bean 정의
@Bean
public TestBean1 java1(){
TestBean1 t1 = new TestBean1();
return t1;
}
}
메소드의 이름으로 해당 빈객체 등록!
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자");
}
}
MainClass.java
//java 파일을 사용하는 방식
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 java1 = ctx2.getBean("java1", TestBean1.class);
System.out.printf("java1: %s\n", java1);
TestBean1 java11 = ctx2.getBean("java1", TestBean1.class);
System.out.printf("java11: %s\n", java11);
ctx2.close();
싱글톤이기에
결과
TestBean1의 생성자
java1: kr.co.softcampus.beans.TestBean1@6392827e
java11: kr.co.softcampus.beans.TestBean1@6392827e
BeanConfigClass.java
@Bean (name="java600")
public TestBean1 java500(){
TestBean1 t1 = new TestBean1();
return t1;
}
MainClass.java
TestBean1 java600 = ctx2.getBean("java600", TestBean1.class);
System.out.printf("java600: %s\n", java600);
Lazy를 붙여주면 xml 로딩할 때 객체 생성 ㄴ
getBean할 때 객체 생성 그 다음에 또 다시 getBean하면 같은 객체 주소값 반환
@Bean
@Lazy
public TestBean2 java2(){
TestBean2 t2 = new TestBean2();
return t2;
}
}
MainClass.java
TestBean2 java2 = ctx2.getBean("java2", TestBean2.class);
System.out.printf("java2 : %s\n", java2);
TestBean2 java22 = ctx2.getBean("java2", TestBean2.class);
System.out.printf("java22 : %s\n", java22);
결과
java2 : kr.co.softcampus.beans.TestBean2@47d9a273
java22 : kr.co.softcampus.beans.TestBean2@47d9a273
@Bean
@Scope("prototype")
public TestBean3 java3() {
TestBean3 t3 = new TestBean3();
return t3;
}
xml 로딩할 때 객체가 생성 안되구, getBean 할 때마다 java3 메소드를 계속 호출함
결과
TestBean3의 생성자
java3 : kr.co.softcampus.beans.TestBean3@59505b48
TestBean3의 생성자
java33 : kr.co.softcampus.beans.TestBean3@4efac082
bean이 xml상에서 딱 하나만 정의되어져있다면, 사실 id가 필요없,,
클래스 type을 가지고 bean 객체를 가지고 왔을 때, bean이 2개 이상 설정 되어있다고하면 원하는 bean에다가 primary="true"를 주면 됨
그러면 똑같은 클래스 type이 여러개 가지고 있다면 true 값을 가지고 있는걸 가지고 나옴
@bean에서는
@Bean
public TestBean4 java4() {
TestBean4 t4 = new TestBean4();
return t4;
}
@Bean
@Primary
public TestBean4 java5() {
TestBean4 t4 = new TestBean4();
return t4;
}
MainClass.java
TestBean4 java4 = ctx2.getBean(TestBean4.class);
System.out.printf("java4 : %s\n", java4);
@ Bean(initMethod="bean2_init", destroyMethod="bean2_destroy");
initMethod를 등록하면 생성자 수행이 완료된 다음에 자동으로 호출됨
MainClass.java
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 java1 = ctx2.getBean("java1", TestBean1.class);
ctx2.close();
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자 입니디");
}
public void init() {
System.out.println("TestBean1의 init 메서드");
}
public void destroy() {
System.out.println("TestBean의 destory 메서드");
}
}
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import kr.co.softcampus.beans.TestBean1;
@Configuration
public class BeanConfigClass {
@Bean(initMethod="init", destroyMethod = "destroy")
@Lazy
public TestBean1 java1() {
return new TestBean1();
}
}
결과
TestBean1의 생성자 입니디
TestBean1의 init 메서드
17:03:02.021 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1ed1993a, started on Sat Dec 24 17:03:01 KST 2022
TestBean의 destory 메서드
Bean에 대한 주입은 생성자를 직접 호출하거나 setter 메서드를 직접 호출하여 값을 주입
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
private int data1;
private String data2;
private DataBean1 data3;
//생성자를 통한 주입
public TestBean1 (int data1, String data2, DataBean1 data3 ) {
this.data1 = data1;
this.data2 = data2;
this.data3 = data3;
}
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
public DataBean1 getData3() {
return data3;
}
public void setData3(DataBean1 data3) {
this.data3 = data3;
}
}
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import kr.co.softcampus.beans.DataBean1;
import kr.co.softcampus.beans.TestBean1;
@Configuration
public class BeanConfigClass {
@Bean
public TestBean1 java1() {
return new TestBean1(200,"문자열2", new DataBean1());
}
}
MainClass.java
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 java1 = ctx2.getBean("java1", TestBean1.class);
System.out.printf("java1.data1 : %d\n", java1.getData1());
System.out.printf("java1.data2 : %s\n", java1.getData2());
System.out.printf("java1.data3 : %s\n", java1.getData3());
ctx2.close();
비교
beans.xml
<bean id='xml1' class='kr.co.softcampus.beans.TestBean1' lazy-init="true">
<constructor-arg value='100' type='int' index='0'/>
<constructor-arg value='문자열1' index='1'/>
<constructor-arg ref='data_bean1' index='2'/>
</bean>
<bean id='data_bean1' class='kr.co.softcampus.beans.DataBean1'/>
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
private int data1;
private String data2;
private DataBean1 data3;
public TestBean1() {
}
// 생성자를 통한 주입
public TestBean1(int data1, String data2, DataBean1 data3) {
this.data1 = data1;
this.data2 = data2;
this.data3 = data3;
}
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public String getData2() {
return data2;
}
public void setData2(String data2) {
this.data2 = data2;
}
public DataBean1 getData3() {
return data3;
}
public void setData3(DataBean1 data3) {
this.data3 = data3;
}
}
BeanConfigClass.java
@Bean
public TestBean1 java2() {
TestBean1 t1 = new TestBean1();
t1.setData1(400);
t1.setData2("문자열4");
t1.setData3(new DataBean1());
return t1;
}
MainClass.java
System.out.println("----------------------------------");
TestBean1 java2 = ctx2.getBean("java2", TestBean1.class);
System.out.printf("java2.data1 : %d\n", java2.getData1());
System.out.printf("java2.data2 : %s\n", java2.getData2());
System.out.printf("java2.data3 : %s\n", java2.getData3());
비교
beans.xml
<bean id='xml2' class='kr.co.softcampus.beans.TestBean1' lazy-init='true'>
<property name="data1" value='300'/>
<property name="data2" value="문자열3"/>
<property name="data3" ref='data_bean1'/>
</bean>
@Bean(autowire = 주입방식) : 자동 주입 방식 설정
Autowire.BY_NAME : 이름을 통한 자동 주입
Autowire.BY_TYPE : 타입을 통한 자동 주입
스프링 5.1부터는 bean에 직접 설정하는 방식을 추천함
BeanConfigClass.java
@Bean
public DataBean2 data1() {
return new DataBean2();
}
@Bean
public DataBean2 data2() {
return new DataBean2();
}
@Bean(autowire = Autowire.BY_NAME)
public TestBean2 java3() {
return new TestBean2();
}
@Bean
public DataBean3 data100() {
return new DataBean3();
}
@Bean(autowire = Autowire.BY_TYPE)
public TestBean3 java4() {
return new TestBean3();
}
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
private DataBean2 data1;
private DataBean2 data2;
public DataBean2 getData1() {
return data1;
}
public void setData1(DataBean2 data1) {
this.data1 = data1;
}
public DataBean2 getData2() {
return data2;
}
public void setData2(DataBean2 data2) {
this.data2 = data2;
}
}
TestBean3.java
package kr.co.softcampus.beans;
public class TestBean3 {
private DataBean3 data1;
private DataBean3 data2;
public DataBean3 getData1() {
return data1;
}
public void setData1(DataBean3 data1) {
this.data1 = data1;
}
public DataBean3 getData2() {
return data2;
}
public void setData2(DataBean3 data2) {
this.data2 = data2;
}
빈 설정 파일에 다음과 같은 코드를 추가하여 빈에 대한 설정을 xml 파일이 아닌 빈 클래스의 어노테이션을 검색해 반영하게 됨.
기본 beans.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean 클래스의 설정되어 있는 어노테이션을 이용한다 -->
<context:annotation-config/>
</beans>
반드시 주입 해야 할 프로퍼티로 설정
@Required
public void setData1(int data1) {
this.data1 = data1;
}
Spring 5.1 ver 부터 deprecated됨. 반드시 주입해야 할 프로퍼티는 생성자 주입을 이용하도록 변경됨
객체 타입을 통해 bean 객체를 자동으로 주입
//변수 타입
@Autowired
private DataClass1 data3;
//setter
@Autowired
public void setData2(DataClass1 data2){
this.data2=data2;
}
//생성자
@Autowired
public TestBean1(DataClass2 data4){
this.data4=data4;
}
Autowired하면 클래스 타입으로 주입됨
Autowired하면 반드시 bean을 정의해줘야함
TestBean1.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Autowired;
public class TestBean1 {
private int data1;
private DataBean1 data2;
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public DataBean1 getData2() {
return data2;
}
// 자동주입(타입)
@Autowired
public void setData2(DataBean1 data2) {
this.data2 = data2;
}
//자동 주입을 변수에 설정
//자동으로 setter 메서드가 추가되어 setter 메서드를 통해 주입 받게 된다.
@Autowired
private DataBean1 data3;
public DataBean1 getData3() {
return data3;
}
}
beans.xml 경우
<bean class='kr.co.softcampus.beans.DataBean1'/>
BeanConfigClass 경우
@Bean
public DataBean1 data_bean1() {
return new DataBean1();
}
@ Autowired로 주입 시 같은 type의 bean이 여러개 정의 되어 있다면 qualifier에 설정 되어 있는 bean을 찾아 주입한다
@Autowired
@Qualifier("obj1")
private DataClass4 data6;
@Autowired
@Qualifier("obj2")
private DataClass4 data7;
beans.xml
<bean id='obj4' class='kr.co.softcampus.beans.DataBean2'/>
<bean id='obj5' class='kr.co.softcampus.beans.DataBean2'/>
BeanConfigClass.java
@Bean
public DataBean2 obj4() {
return new DataBean2();
}
@Bean
public DataBean2 obj5() {
return new DataBean2();
}
TestBean1.java
@Autowired
@Qualifier("obj4")
private DataBean2 data4;
@Autowired
@Qualifier("obj5")
private DataBean2 data5;
public DataBean2 getData4() {
return data4;
}
public DataBean2 getData5() {
return data5;
}
get만 설정!
+) 이 값이 있으면 넣고 없으면 말구 ~ ~ ~ ~
@Autowired(required=false)
@Qualifier("obj6")
private DataBean2 data6;
마찬가지로 get만 설정~~
생성자에 주입 시 참조 변수 타입 변수들은 자동으로 주입되고 기본 자료형 및 문자열 값만 주입을 설정 해주면 된다.
자동 주입이 발생하게 될 때 Type을 가지고 주입하게 됨.
<!-- bean 클래스의 설정되어 있는 어노테이션을 이용한다 -->
<context:annotation-config/>
이거보고 자동으로 주입해줌
기본 자료형 같은 경우는 값을 직접 지정
TestBean2.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Value;
public class TestBean2 {
private int data1;
private String data2;
private DataBean3 data3;
private DataBean4 data4;
public TestBean2(@Value("100") int data1, @Value("문자열") String data2, DataBean3 data3, DataBean4 data4) {
this.data1=data1;
this.data2=data2;
this.data3=data3;
this.data4=data4;
}
public TestBean2() {
// TODO Auto-generated constructor stub
}
public int getData1() {
return data1;
}
public String getData2() {
return data2;
}
public DataBean3 getData3() {
return data3;
}
public DataBean4 getData4() {
return data4;
}
}
beans.xml
<bean id ='xml2' class='kr.co.softcampus.beans.TestBean2'/>
<bean class="kr.co.softcampus.beans.DataBean3"/>
<bean class="kr.co.softcampus.beans.DataBean4"/>
BeanConfigClass.java
@Bean
public TestBean2 java2() {
return new TestBean2();
}
Main.
TestBean2 java2=ctx2.getBean("java2", TestBean2.class);
System.out.printf("java2.data1: %d\n", java2.getData1());
System.out.printf("java2.data2: %s\n", java2.getData2());
System.out.printf("java2.data3 : %s\n", java2.getData3());
System.out.printf("java2.data4 : %s\n", java2.getData4());
BeanConfigClass는 생성자를 통해서 아무것도 자동주입되지않는걸 볼 수 있음
결과
java2.data1: 0
java2.data2: null
java2.data3 : null
java2.data4 : null
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.beans.TestBean2;
import kr.co.softcampus.config.BeanConfigClass;
public class MainClass {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx1 = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 xml1 = ctx1.getBean("xml1", TestBean1.class);
System.out.printf("xml1.data1 : %d\n", xml1.getData1());
System.out.printf("xml1.data2 : %s\n", xml1.getData2());
System.out.printf("xml1.data3 : %s\n", xml1.getData3());
System.out.printf("xml1.data4 : %s\n", xml1.getData4());
System.out.printf("xml1.data5 : %s\n", xml1.getData5());
System.out.printf("xml1.data6 : %s\n", xml1.getData6());
TestBean2 xml2 = ctx1.getBean("xml2", TestBean2.class);
System.out.printf("xml2.data1 : %d\n", xml2.getData1());
System.out.printf("xml2.data2 : %s\n", xml2.getData2());
System.out.printf("xml2.data3 : %s\n", xml2.getData3());
System.out.printf("xml2.data4 : %s\n", xml2.getData4());
ctx1.close();
System.out.println("================");
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 java1 = ctx2.getBean("java1", TestBean1.class);
System.out.printf("java1.data1 : %d\n", java1.getData1());
System.out.printf("java1.data2 : %s\n", java1.getData2());
System.out.printf("java1.data3 : %s\n", java1.getData3());
System.out.printf("java1.data4 : %s\n", java1.getData4());
System.out.printf("java1.data5 : %s\n", java1.getData5());
System.out.printf("java1.data6 : %s\n", java1.getData6());
TestBean2 java2=ctx2.getBean("java2", TestBean2.class);
System.out.printf("java2.data1: %d\n", java2.getData1());
System.out.printf("java2.data2: %s\n", java2.getData2());
System.out.printf("java2.data3 : %s\n", java2.getData3());
System.out.printf("java2.data4 : %s\n", java2.getData4());
ctx2.close();
}
}
beans.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- bean 클래스의 설정되어 있는 어노테이션을 이용한다 -->
<context:annotation-config/>
<bean id='xml1' class='kr.co.softcampus.beans.TestBean1'/>
<bean class='kr.co.softcampus.beans.DataBean1'/>
<bean id='obj4' class='kr.co.softcampus.beans.DataBean2'/>
<bean id='obj5' class='kr.co.softcampus.beans.DataBean2'/>
<bean id ='xml2' class='kr.co.softcampus.beans.TestBean2'/>
<bean class="kr.co.softcampus.beans.DataBean3"/>
<bean class="kr.co.softcampus.beans.DataBean4"/>
</beans>
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import kr.co.softcampus.beans.DataBean1;
import kr.co.softcampus.beans.DataBean2;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.beans.TestBean2;
@Configuration
public class BeanConfigClass {
@Bean
public TestBean1 java1() {
return new TestBean1();
}
@Bean
public DataBean1 data_bean1() {
return new DataBean1();
}
@Bean
public DataBean2 obj4() {
return new DataBean2();
}
@Bean
public DataBean2 obj5() {
return new DataBean2();
}
@Bean
public TestBean2 java2() {
return new TestBean2();
}
}
TestBean1.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class TestBean1 {
private int data1;
private DataBean1 data2;
//자동 주입을 변수에 설정
//자동으로 setter 메서드가 추가되어 setter 메서드를 통해 주입 받게 된다.
@Autowired
private DataBean1 data3;
@Autowired
@Qualifier("obj4")
private DataBean2 data4;
@Autowired
@Qualifier("obj5")
private DataBean2 data5;
@Autowired(required=false)
@Qualifier("obj6")
private DataBean2 data6;
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public DataBean1 getData2() {
return data2;
}
// 자동주입(타입)
@Autowired
public void setData2(DataBean1 data2) {
this.data2 = data2;
}
public DataBean1 getData3() {
return data3;
}
public DataBean2 getData4() {
return data4;
}
public DataBean2 getData5() {
return data5;
}
public DataBean2 getData6() {
return data6;
}
}
TestBean2.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Value;
public class TestBean2 {
private int data1;
private String data2;
private DataBean3 data3;
private DataBean4 data4;
public TestBean2(@Value("100") int data1, @Value("문자열") String data2, DataBean3 data3, DataBean4 data4) {
this.data1=data1;
this.data2=data2;
this.data3=data3;
this.data4=data4;
}
public TestBean2() {
// TODO Auto-generated constructor stub
}
public int getData1() {
return data1;
}
public String getData2() {
return data2;
}
public DataBean3 getData3() {
return data3;
}
public DataBean4 getData4() {
return data4;
}
}
적용을 위해서는 반드시 라이브러리 추가해야함!
생성자 호출 후 자동으로 호출될 함수를 등록
객체 소멸 전 자동으로 호출될 함수를 등록
1) BeanConfig에 쓰는 경우
@Bean(initMethod = "init1", destroyMethod="destroy1")
@Lazy
public TestBean1 obj1() {
return new TestBean1();
}
TestBean1.java
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자");
}
public void init1() {
System.out.println("TestBean1의 init");
}
public void destroy1() {
System.out.println("TestBean1의 destroy");
}
}
2) 직접 쓰는 경우
TestBean2.java
public class TestBean2 {
public TestBean2() {
System.out.println("TestBean2의 생성자 ");
}
//생성자 호출 이후 자동으로 호출
@PostConstruct
public void init2() {
System.out.println("TestBean2의 init 메서드");
}
// 객체 소멸되기 전 자동으로 호출됨
@PreDestroy
public void destroy2() {
System.out.println("TestBean2의 destroy 메서드");
}
}
BeanConfigClass.java
@Bean
@Lazy
public TestBean2 obj2() {
return new TestBean2();
}
Bean의 이름을 통해 주입
TestBean5.java
public class TestBean5 {
// 변수의 이름과 동일한 이름의 Bean이 주입됨
@Resource
private DataBean1 data1;
@Resource
private DataBean2 data2;
public DataBean1 getData1() {
return data1;
}
public DataBean2 getData2() {
return data2;
}
}
BeanConfigClass
@Bean
public TestBean5 obj5() {
return new TestBean5();
}
Main
TestBean5 obj5 = ctx.getBean("obj5", TestBean5.class);
System.out.printf("obj5.data1 : %s\n", obj5.getData1());
System.out.printf("obj5.data2 : %s\n", obj5.getData2());
만약 bean의 이름과 변수의 이름이 동일하지않은경우
public class TestBean6 {
@Resource(name ="data1")
private DataBean1 data100;
@Resource(name ="data2")
private DataBean2 data200;
public DataBean1 getData100() {
return data100;
}
public DataBean2 getData200() {
return data200;
}
Main
TestBean6 obj6 = ctx.getBean("obj6", TestBean6.class);
System.out.printf("obj6.data1 : %s\n", obj6.getData100());
System.out.printf("obj6.data2 : %s\n", obj6.getData200());
Component를 사용하면 Bean 등록하는 것 자체를 만드는 bean 클래스 자체에다가 할 수 있음
pom.xml
<javax.annotation-version>1.3.2</javax.annotation-version>
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation-version}</version>
</dependency>
@Component 어노테이션을 사용하면 Bean Configuration 파일에 Bean을 등록하지 않아도 자동으로 등록됨
<context:component-scan base-package="kr.co.softcampus.beans"/>
<context:component-scan base-package="kr.co.softcampus.bean2"/>
@ComponentScan(basePackages = {"kr.co.softcampus.beans", "kr.co.softcampus.bean2"});
//Bean으로 등록한다.
//이름이 없기 때문에 타입을 통해서 받아 낼 수 있다.
@Component
public class TestBean3 {
}
@Bean: 개발자가 class의 코드를 수정할 수 없는 경우, 같은 클래스 타입의 bean을 여러개 등록할 경우
@Component: 개발자가 Class의 코드를 수정할 수 있는 경우
@Component 어노테이션만 사용하면 타입을 통해 Bean 객체를 가져올 수 있다
@Component
public class TestBean1 {
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.config.BeanConfigClass;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 t1 = ctx.getBean(TestBean1.class);
System.out.printf("t1: %s\n", t1);
TestBean1 t2 = ctx.getBean(TestBean1.class);
System.out.printf("t2: %s\n", t2);
ctx.close();
}
}
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "kr.co.softcampus.beans")
public class BeanConfigClass {
}
TestBean1.java
package kr.co.softcampus.beans;
import org.springframework.stereotype.Component;
// IoC 컨테이너 객체를 생성할 때 자동으로 객체가 생성된다.
// 타입을 통해 등록된 Bean 객체를 가져올 수 있다
// SingleTon
@Component
public class TestBean1 {
public TestBean1() {
System.out.println("TestBean1의 생성자");
}
}
결과
TestBean1의 생성자
t1: kr.co.softcampus.beans.TestBean1@28701274
t2: kr.co.softcampus.beans.TestBean1@28701274
설정한 이름으로 Bean 객체를 가져올 수 있다
@Component ("t2")
public class TestBean2{}
// IoC 컨테이너가 만들어 질 때 자동으로 객체가 생성된다.
// 객체의 주소값을 가져올 때 이름을 통해서 가져올 수 있다.
// Singleton
@Component("t3")
public class TestBean2 {
public TestBean2() {
System.out.println("TestBean2의 생성자");
}
}
getBean 메서드를 호출할 때 객체가 생성됨
@Component
@Lazy
public class TestBean3 {
}
@Scope("prototype")
prototype으로 설정
getBean할 때마다 객체 생성됨
@Component
//getBean 메서드를 호출할 때 마다 새로운 객체를 생성해 반환.
@Scope("prototype")
public class TestBean4 {
public TestBean4() {
System.out.println("TestBean4의 생성자");
}
}
TestBean4 t9 = ctx.getBean(TestBean4.class);
System.out.printf("t9: %s\n", t9);
TestBean4 t10 = ctx.getBean(TestBean4.class);
System.out.printf("t10 : %s\n", t10);
결과
TestBean4의 생성자
t9: kr.co.softcampus.beans.TestBean4@d35dea7
TestBean4의 생성자
t10 : kr.co.softcampus.beans.TestBean4@7770f470
생성자 호출 이후 자동으로 호출될 메서드와 객체가 소멸될 때 자동으로 호출되는 메서드를 등록한다
@PostConstruct
public void init(){
System.out.println("init 메서드 호출");
}
@PreDestroy
public void destroy(){
System.out.println("destroy 메서드 호출");
}
TestBean5.java
@Component
@Lazy
public class TestBean5 {
public TestBean5() {
System.out.println("TestBean5의 생성자");
}
@PostConstruct
public void init() {
System.out.println("init");
}
@PreDestroy
public void destroy() {
System.out.println("destroy 메서드가 호출되었습니다");
}
}
@Bean을 통해 설정했던 주입과 동일한 방식을 이용한다.
@Autowired : 타입을 통한 자동 주입
@Qualifier : 이름을 통한 자동 주입
생성자의 경우 타입이 같은 Bean을 찾아 자동으로 주입한다.
@Autowired를 변수에다가 붙이면 나중에 compile할 때 setter가 자동으로 만들어짐
그래서 getter만 추가
이름을 가지고 주입한다는 의미는 bean을 ㄹ등록할 때 이름을 부여한다는 의미는 같은 클래스 타입의 빈을 여러개를 등록해서 사용할 경우 그럴 때 이름을 부여하는 경우 많다
DataBean1.java
@Component
public class DataBean1 {
}
DataBean2.java
@Component("obj2")
public class DataBean2 {
}
DataBean3.java
@Component("obj3")
public class DataBean3 {
}
TestBean1.java
package kr.co.softcampus.beans;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class TestBean1 {
@Autowired
private DataBean1 data1;
@Autowired
@Qualifier("obj2")
private DataBean2 data2;
@Resource(name="obj3")
private DataBean3 data3;
@Resource(name="obj4")
private DataBean3 data4;
@Resource(name="obj5")
private DataBean3 data5;
public DataBean1 getData1() {
return data1;
}
public DataBean2 getData2() {
return data2;
}
public DataBean3 getData3() {
return data3;
}
public DataBean3 getData4() {
return data4;
}
public DataBean3 getData5() {
return data5;
}
}
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import kr.co.softcampus.beans.DataBean3;
@Configuration
@ComponentScan(basePackages = "kr.co.softcampus.beans")
public class BeanConfigClass{
@Bean
public DataBean3 obj4() {
return new DataBean3();
}
@Bean
public DataBean3 obj5() {
return new DataBean3();
}
}
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.config.BeanConfigClass;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 t1 = ctx.getBean(TestBean1.class);
System.out.printf("t1.data1 : %s\n", t1.getData1());
System.out.printf("t1.data2 : %s\n", t1.getData2());
System.out.printf("t1.data3 : %s\n", t1.getData3());
System.out.printf("t1.data4 : %s\n", t1.getData4());
System.out.printf("t1.data5 : %s\n", t1.getData5());
ctx.close();
}
}
반드시 주입받아야되는게 있으면 생성자를 통한 주입을 추천
DataBean4
package kr.co.softcampus.beans;
import org.springframework.stereotype.Component;
@Component
public class DataBean4 {
}
DataBean5
package kr.co.softcampus.beans;
import org.springframework.stereotype.Component;
@Component
public class DataBean5 {
}
TestBean2.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class TestBean2 {
private int data1;
private String data2;
private DataBean4 data3;
private DataBean5 data4;
public TestBean2(@Value("100") int data1, @Value("문자열") String data2, DataBean4 data3, DataBean5 data4) {
this.data1 = data1;
this.data2 = data2;
this.data3 = data3;
this.data4 = data4;
}
public int getData1() {
return data1;
}
public String getData2() {
return data2;
}
public DataBean4 getData3() {
return data3;
}
public DataBean5 getData4() {
return data4;
}
}
MainClass.java
TestBean2 t2 = ctx.getBean(TestBean2.class);
System.out.printf("t2.data1 : %s\n", t2.getData1());
System.out.printf("t2.data2 : %s\n", t2.getData2());
System.out.printf("t2.data3 : %s\n", t2.getData3());
System.out.printf("t2.data4 : %s\n", t2.getData4());
TestBean3.java
package kr.co.softcampus.beans;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class TestBean3 {
private int data1;
private String data2;
private DataBean4 data3;
private DataBean5 data4;
public TestBean3 (@Value("100") int data1, @Value("문자열") String data2, DataBean4 data3, DataBean5 data4) {
this.data1 = data1;
this.data2 = data2;
this.data3 = data3;
this.data4 = data4;
}
public int getData1() {
return data1;
}
public String getData2() {
return data2;
}
public DataBean4 getData3() {
return data3;
}
public DataBean5 getData4() {
return data4;
}
}
BeanConfigClass
@Bean
public TestBean3 java2() {
TestBean3 t2 = new TestBean3(200,"문자열2", new DataBean4(), new DataBean5());
return t2;
}
MainClass
TestBean3 java2 = ctx.getBean("java2", TestBean3.class);
System.out.printf("java2.data1 : %d\n", java2.getData1());
System.out.printf("java2.data2:%s\n", java2.getData2());
System.out.printf("java2.data3:%s\n", java2.getData3());
System.out.printf("java2.data4:%s\n", java2.getData4());
java 파일에다가 다 작성하는 방식으로 바뀌는 중 응ㅇ
Aspect Oriented Programming 관점 지향 프로그래밍
하나의 프로그램을 관점이라는 논리적인 단위로 분리하여 관리하는 개념
로깅, 검사 등 다양한 곳에서 사용되고 있다.
여기에서는 메서드 호출을 관심사로 설정하여 AOP에 관한 실습을 진행한다
관심사를 통해 Spring FrameWork가 어떤 메서드가 호출되는 지 관심있게 지켜보다가 특정 메서드가 호출되면 자동으로 메서드 전과 후에 다른 메서드가 호출될 수 있도록 한다.
Join Point 모듈이 삽입되어 동작하게 되는 특정 위치 (메서드 호출 등)
Point Cut : 다양한 Joint Point 중에 어떤 것을 사용할 지 선택
Advice : Join Point에 삽입되어 동작할 수 있는 코드
관심있는 호출된 메서드 말고 다른 메서드 호출하고 호출되는 메서드를 어드바이서
Weaving : Advice를 핵심 로직 코드에 적용하는 것
Aspect: Point Cut + Advice
before: 메서드 호출 전에 동작하는 Advice
after-returning: 예외 없이 호출된 메서드의 동작이 완료되면 동작하는 Advice
after-throwing: 호출된 메서드 동작 중 예외가 발생했을 때 동작하는 Advice
after: 예외 발생 여부에 관계없이 호출된 메서드의 동작이 완료되면 동작하는 Advice
around: 메서드 호출 전과 후에 동작하는 Advice
XML을 이용한 구현방법
@AspectJ 어노테이션을 이용한 구현방법
라이브러리 추가
<dependency>
<groupId>org.asepctj</groupId>
<artifcatId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
모든 패키지에 모든 클래스에 있는 package1을 호출하는 행위 그자체를 관심사로 설정
expression="execution(* method1()) "/>
요 관심사가 동작을 하면 advior1이 가지고 있는 beforeMethod를 호출해라!
<aop:before method="beforeMethod" pointcut-ref="point1"/>
Bean 안에 들어있는 이 메서드를 호출해라~
beans.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id='xml1' class='kr.co.softcampus.beans.TestBean'/>
<bean id ='advisor1' class='kr.co.softcampus.advisor.AdvisorClass'/>
<aop:config>
<aop:aspect ref='advisor1'>
<aop:pointcut id="point1" expression="execution(* method1())"/>
<aop:before method="beforeMethod" pointcut-ref="point1"/>
<aop:after method="afterMethod" pointcut-ref="point1"/>
</aop:aspect>
</aop:config>
</beans>
ref를 통해서 id가 이거인 bean에 접근을 하고, pointcutid를 통해서 point1에 해당하는 method를 찾아서 언제 호출할건지를 설정해줌!
Mainclass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean bean1 = ctx.getBean("xml1", TestBean.class);
bean1.method1(); // 메서드1호출 행위 = 관심사로 등록되어지는 행위가 발생하게 됨
ctx.close();
}
}
AdvisorClass.java
public class AdvisorClass {
public void beforeMethod() {
System.out.println("beforeMethod 호출");
}
public void afterMethod() {
System.out.println("afterMethod 호출");
}
}
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
public void method1() {
System.out.println("method1 호출");
}
}
MainClass.java
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean bean1 = ctx.getBean("xml1", TestBean.class);
int a1 = bean1.method1(); // 메서드1호출 행위 = 관심사로 등록되어지는 행위가 발생하게 됨
System.out.printf("al : %d\n", a1);
ctx.close();
TestBean.java
package kr.co.softcampus.beans;
public class TestBean {
public int method1() {
System.out.println("method1 호출");
return 100;
}
}
AdvisorClass
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("aroundMethod 호출1");
//원래의 메서드를 호출한다.
Object obj = pjp.proceed();
System.out.println("aroundMethod 호출2");
return obj;
}
Method가 아무 문제 없이 정상적으로 잘 끝났을 때 ,,
AdvisorClass.java
public void afterReturningMethod() {
System.out.println("afterReturningMethod 호출");
}
beans.xml
<aop:after-returning method="afterReturningMethod" pointcut-ref="point1"/>
예외발생시 수행될 메소드
AdvisorClass.java
public void afterThrowingMethod(Throwable e1) {
System.out.println("afterThrowingMethod 호출");
System.out.println(e1);
}
beans.xml
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="point1" throwing="a1"/>
Pointcut을 지정할 때 사용하는 문법
execution(접근제한자 리턴타입 클래스이름 메서드이름(매개변수))
접근 제한자: public만 지원된다.
리턴 타입: 메서드의 매개변수 타입
클래스 이름: 패키지를 포함한 클래스 이름
메서드 이름: 메서드의 이름
매개변수: 매개변수의 형태
*: 하나의 모든것을 의미
..: 개수 상관없이 모든 것을 의미
package kr.co.softcampus.advisor;
public class AdvisorClass {
public void beforeMethod() {
System.out.println("beforeMethod 호출");
}
}
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public void method1() {
System.out.println("beans.TestBean1.method1()");
}
}
return type이 void package는 package kr.co.softcampus.beans.TestBean에
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1 클래스, method1 메서드, 메개변수 없음 -->
<aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1())"/>
리턴 타입, 클래스 이름, 메서드 이름, 매개변수
beans.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id='xml1' class='kr.co.softcampus.beans.TestBean1' />
<bean id='xml2' class='kr.co.softcampus.beans.TestBean2' />
<bean id='xml3' class='kr.co.softcampus.beans2.TestBean1' />
<bean id='advisor1' class='kr.co.softcampus.advisor.AdvisorClass' />
<aop:config>
<aop:aspect ref='advisor1'>
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1 클래스, method1 메서드, 매개변수
없음 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1())"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1 클래스, method1 메서드, 정수형
매개변수 1개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(int))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1 클래스, method1 메서드, String
타입 매개변수 1개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(java.lang.String))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, method1 메서드, 모든
타입의 매개변수 1개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(*))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, method1 메서드, 정수형
매개변수 2개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(int,
int))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, method1 메서드, 정수형
매개변수 1개, String 타입 매개변수 1개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(int,
java.lang.String))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, method1 메서드, 모든
타입의 매개변수 2개 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(*,
*))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, method1메서드, 모든 타입의
매개변수 0개이상 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.method1(..))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans.TestBean1클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.TestBean1.*(..))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans 패키지의 모든 클래스, method1 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.*.method1(..))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.beans 패키지의 모든 클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.beans.*.*(..))"/> -->
<!-- 반환타입이 void, kr.co.softcampus.의 모든 패키지의 모든클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(void kr.co.softcampus.*.*.*(..))"/> -->
<!-- 반환타입이 void, 모든 패키지, 모든 클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(void *.*(..))"/> -->
<!-- 반환타입이 int, 모든 패키지, 모든 클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(int *.*(..))"/> -->
<!-- 모든 반환타입, 모든 패키지, 모든 클래스, 모든 메서드 -->
<!-- <aop:pointcut id="point1" expression="execution(* *.*(..))"/> -->
<aop:pointcut id="point1"
expression="execution(* method1(..))" />
<aop:before method="beforeMethod" pointcut-ref="point1" />
</aop:aspect>
</aop:config>
</beans>
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.beans.TestBean2;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 xml1 = ctx.getBean("xml1", TestBean1.class);
TestBean2 xml2 = ctx.getBean("xml2", TestBean2.class);
kr.co.softcampus.beans2.TestBean1 xml3 = ctx.getBean("xml3", kr.co.softcampus.beans2.TestBean1.class);
xml1.method1();
System.out.println("----------------------");
xml1.method1(100);
System.out.println("----------------------");
xml1.method1("문자열");
System.out.println("----------------------");
xml1.method1(100, 200);
System.out.println("----------------------");
xml1.method1(100, "문자열");
System.out.println("----------------------");
xml1.method2();
System.out.println("----------------------");
xml2.method1();
System.out.println("----------------------");
xml3.method1();
System.out.println("----------------------");
int a1 = xml1.method3();
System.out.printf("a1 : %d\n", a1);
ctx.close();
}
}
TestBean1.java
package kr.co.softcampus.beans;
public class TestBean1 {
public void method1() {
System.out.println("beans.TestBean1.method1()");
}
public void method1(int a1) {
System.out.println("beans.TestBean1.method1(int)");
}
public void method1(String a2) {
System.out.println("beans.TestBean1.method1(java.lang.String)");
}
public void method1(int a1, int a2) {
System.out.println("beans.TestBean1.method1(int, int)");
}
public void method1(int a1, String a2) {
System.out.println("beans.TestBean1.method1(int, String)");
}
public void method2() {
System.out.println("beans.TestBean1.method2()");
}
public int method3() {
System.out.println("int beans.TestBean1.method3()");
return 100;
}
}
TestBean2.java
package kr.co.softcampus.beans;
public class TestBean2 {
public void method1() {
System.out.println("beans.TestBean2.method1()");
}
}
Advisor.class
package kr.co.softcampus.advisor;
//import org.aspectj.lang.ProceedingJoinPoint;
public class AdvisorClass {
public void beforeMethod() {
System.out.println("beforeMethod 호출");
}
}
@AspectJ 어노테이션을 활용해 Advsior 역할을 할 Bean을 설정할 수 있다.
xml을 통해서 bean을 설정할 때 -> <aop:asepctj-autoproxy/>
java를 통해서 bean을 설정할 때 -> @EnableAspectAutoProxy
@Before 관심사 동작 이전에 호출된다
@After 관심사 동작 이후에 호출된다
@Around 관심사 동작 이전 이후를 의미
@AfterReturning 예외 없이 정상적으로 종료되었을 때 호출된다
@AfterThrowing 예외가 발생하여 종료되었을 때 호출된다
advisorClass.java자체에다가 만들자
AdvisorClass.java
package kr.co.softcampus.advisor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AdvisorClass {
@Before("execution(* method1())")
public void beforeMethod() {
System.out.println("beforeMethod 호출");
}
@After("execution(* method1())")
public void afterMethod() {
System.out.println("afterMethod 호출");
}
@Around("execution(* method1())")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("aroundMethod 호출 1");
Object result = pjp.proceed();
System.out.println("aroundMethod 호출 2");
return result;
}
@AfterReturning("execution(* method1())")
public void afterReturningMethod() {
System.out.println("afterReturning 호출");
}
@AfterThrowing("execution(* method1())")
public void afterThrowingMethod() {
System.out.println("afterThrowing 호출");
}
}
TestBean1.java
package kr.co.softcampus.beans;
import org.springframework.stereotype.Component;
@Component
public class TestBean1 {
public void method1() throws Exception{
System.out.println("TestBean1의 method1 호출");
//int a1 = 10 / 0;
}
}
BeanConfigClass.java
package kr.co.softcampus.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"kr.co.softcampus.beans", "kr.co.softcampus.advisor"})
@EnableAspectJAutoProxy
public class BeanConfigClass {
}
beans.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="kr.co.softcampus.beans"/>
<context:component-scan base-package="kr.co.softcampus.advisor"/>
<!-- advisor 클래스에 설정되어 있는 Annoation을 분석하여 AOP 셋팅을 해라 -->
<aop:aspectj-autoproxy/>
</beans>
MainClass.java
package kr.co.softcampus.main;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import kr.co.softcampus.beans.TestBean1;
import kr.co.softcampus.config.BeanConfigClass;
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
ClassPathXmlApplicationContext ctx1 = new ClassPathXmlApplicationContext("kr/co/softcampus/config/beans.xml");
TestBean1 xml1 = ctx1.getBean(TestBean1.class);
try {
xml1.method1();
}catch(Exception e) {
}
ctx1.close();
System.out.println("========================================");
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(BeanConfigClass.class);
TestBean1 java1 = ctx2.getBean(TestBean1.class);
try {
java1.method1();
}catch(Exception e) {
e.printStackTrace();
}
ctx2.close();
}
}
create table jdbc_table(
int_data number not null,
str_data varchar2(500) not null
);
Spring Framework는 JDBC 프로그래밍을 위해 JdbcTemplate 클래스를 제공하고 있다
JdbcTemplate 클래스는 SQL 쿼리문을 손쉽게 구현할 수 있도록 구현되어 있다.
<!-- oracle jdbc -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>${com.oracle-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${org.apache.commons-version}</version>
</dependency>
</dependencies>
</project>
BeanConfigClass
package kr.co.softcampus.config;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
@Configuration
@ComponentScan(basePackages = {"kr.co.softcampus.beans", "kr.co.softcampus.db"})
public class BeanConfigClass {
// DataSource
@Bean
public BasicDataSource source() {
BasicDataSource source = new BasicDataSource();
source.setDriverClassName("oracle.jdbc.OracleDriver");
source.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
source.setUsername("scott");
source.setPassword("1234");
return source;
}
// 데이터베이스에 접속해서 쿼리를 전달하는 빈을 등록한다.
@Bean
public JdbcTemplate db(BasicDataSource source) {
JdbcTemplate db = new JdbcTemplate(source);
return db;
}
}
Jdbc DAO
package kr.co.softcampus.db;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import kr.co.softcampus.beans.JdbcBean;
@Component
public class JdbcDAO {
// JDBC 관리 객체를 주입 받는다.
@Autowired
private JdbcTemplate db;
// Mapper를 주입받는다.
@Autowired
private MapperClass mapper;
// 저장
public void insert_data(JdbcBean bean) {
String sql = "insert into jdbc_table (int_data, str_data) values (?, ?)";
db.update(sql, bean.getInt_data(), bean.getStr_data());
}
// 가져오기
public List<JdbcBean> select_data(){
String sql = "select int_data, str_data from jdbc_table";
List<JdbcBean> list = db.query(sql, mapper);
return list;
}
// 수정
public void update_data(JdbcBean bean) {
String sql = "update jdbc_table set str_data = ? where int_data = ?";
db.update(sql, bean.getStr_data(), bean.getInt_data());
}
// 삭제
public void delete_data(int int_data) {
String sql = "delete from jdbc_table where int_data = ?";
db.update(sql, int_data);
}
}
Select 문을 데이터를 가져올 때 어떤 컬럼의 값을 bean 어디에 주입할 것인지 결정을 해줘야 하는데 이 역할을 하는 클래스를 Mapper class라고 부른다.
@Component
public class MapperClass implements RowMapper<JdbcBean> {
public JdbcBean mapRow(ResultSet rs, int rowNum) throws SQLException {
// TODO Auto-generated method stub
JdbcBean bean = new JdbcBean();
bean.setInt_data(rs.getInt("int_data"));
bean.setStr_data(rs.getString("str_data"));
return bean;
}
}
MainClass.java
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
// dao를 가져온다.
JdbcDAO dao = ctx.getBean(JdbcDAO.class);
// insert
// JdbcBean bean1 = new JdbcBean();
// bean1.setInt_data(1);
// bean1.setStr_data("문자열1");
// dao.insert_data(bean1);
//
// JdbcBean bean2 = new JdbcBean();
// bean2.setInt_data(2);
// bean2.setStr_data("문자열2");
// dao.insert_data(bean2);
//
// System.out.println("저장완료");
// update
// JdbcBean bean4 = new JdbcBean();
// bean4.setInt_data(1);
// bean4.setStr_data("문자열3");
// dao.update_data(bean4);
// delete
dao.delete_data(1);
// select
List<JdbcBean> list = dao.select_data();
for(JdbcBean bean3 : list) {
System.out.printf("int_data : %d\n", bean3.getInt_data());
System.out.printf("str_data : %s\n", bean3.getStr_data());
System.out.println("----------------------------------------");
}
ctx.close();
}
}
Spring Framework에서 제공하는 JDBC 라이브러리를 보다 쉽게 작업할 수 있도록 만든 라이브러리
Mapper의 역할을 확장하여 쿼리문 작성을 모두 Mapper에서 할 수 있도록 지원
Spring Framework의 대표작은 JDBC 라이브러리
mybatis는 반드시 자바 8.0 이상이여함
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${org.mybatis-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
BeanConfigClass.java
@Configuration
@ComponentScan(basePackages = "kr.co.softcampus.beans")
public class BeanConfigClass {
// data source
@Bean
public BasicDataSource dataSource() {
BasicDataSource source = new BasicDataSource();
source.setDriverClassName("oracle.jdbc.OracleDriver");
source.setUrl("jdbc:oracle:thin:@localhost:1521:orcl");
source.setUsername("scott");
source.setPassword("1234");
return source;
}
// SqlSessionFactory : jdbc를 처리하는 객체
@Bean
public SqlSessionFactory factory(BasicDataSource source) throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(source);
SqlSessionFactory factory = factoryBean.getObject();
return factory;
}
// Mapper
@Bean
public MapperFactoryBean<MapperInterface> test_mapper(SqlSessionFactory factory) throws Exception{
MapperFactoryBean<MapperInterface> factoryBean = new MapperFactoryBean<MapperInterface>(MapperInterface.class);
factoryBean.setSqlSessionFactory(factory);
return factoryBean;
}
}
MapperInterface.java
public interface MapperInterface {
/*
@Results({
@Result(column = "int_data", property = "int_data"),
@Result(column = "str_data", property = "str_data")
})
str 컬럼의 값은 지정된 빈의 str_data에 넣겠다
보통 컬럼의 이름과 property 이름이 같은거는 생략해도 알아서 넣어줌
*/
@Select("select int_data, str_data from jdbc_table")
List<JdbcBean> select_data();
@Insert("insert into jdbc_table (int_data, str_data) values (#{int_data}, #{str_data})")
void insert_data(JdbcBean bean);
@Update("update jdbc_table set str_data = #{str_data} where int_data = #{int_data}")
void update_data(JdbcBean bean);
@Delete("delete from jdbc_table where int_data = #{abc}")
void delete_data(int int_data);
}
JdbcBean bean이 가지고 있는 str data와 int data를 바인딩 시키는 것
MainClass.java
public class MainClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfigClass.class);
MapperInterface mapper = ctx.getBean("test_mapper", MapperInterface.class);
// insert
// JdbcBean bean2 = new JdbcBean();
// bean2.setInt_data(100);
// bean2.setStr_data("문자열100");
// mapper.insert_data(bean2);
//
// JdbcBean bean3 = new JdbcBean();
// bean3.setInt_data(200);
// bean3.setStr_data("문자열200");
// mapper.insert_data(bean3);
// update
// JdbcBean bean4 = new JdbcBean();
// bean4.setInt_data(100);
// bean4.setStr_data("문자열300");
// mapper.update_data(bean4);
// delete
mapper.delete_data(100);
// select
List<JdbcBean> list1 = mapper.select_data();
for(JdbcBean bean1 : list1) {
System.out.printf("int_data : %d\n", bean1.getInt_data());
System.out.printf("str_data : %s\n", bean1.getStr_data());
System.out.println("--------------------------------------");
}
ctx.close();
}
}
JdbcBean.java
@Component
@Scope("prototype")
public class JdbcBean {
private int int_data;
private String str_data;
public int getInt_data() {
return int_data;
}
public void setInt_data(int int_data) {
this.int_data = int_data;
}
public String getStr_data() {
return str_data;
}
public void setStr_data(String str_data) {
this.str_data = str_data;
}
}