자바 빈의 규약! 표준화


어째서 빈컨테이너는 공통상위 클래스(추상), 인터페이스 클래스 없이 빈 객체를 관리 할 수 있을까?

클래스의 메소드와 기능을 런타임에 노출 시킬 수 있게 하는 기능을 introspection이라 한다. 

그렇다면 introspection은 어떻게 구현되어 있나? 바로 java.lang.reflection 패키지를 사용한다.

빈 컨테이너는 자바빈즈에 api에서 정의된 기준에 맞는 public 메소드를 분석하여, 주어진 빈이 지원하는 프로퍼티를 알아낸다.

그럼으로 빈 클래스는 자신이 제공하는 프로퍼티에 대해서 
1.게터,세터를 제공해야 한다. (약속:set/get +프로퍼티이름 )
2.매개변수 없는 디폴트 생성자를 제공해야 한다. (분명 매개변수 있는 생성자도 reflect로 찾을수 있고 사용할수 있는데..? 
  표준화 하다 보니까 디폴트 생성자로 구현한건가?)
(etc)public 으로 노출해주는 것도.. modify 받아서 accesible인가를 바꿔주면 다 뚤을수 있음.. class를 구성하는 Class(타입)
      , modifyer(접근자), 각종 데이터, 각종 메서드가 모두 object 타입으로 포섭이 가능하니... 장점도 있지만, 단점도 있다.
  
      한마디로 reflect 이용하면 클래스를 사용(생성,세팅,메소드이용등)하거나 완전히 수정할수 있음
      (인터럽트해서 수정해서 악용한다. = 해킹이군.. 그럼으로 각종 보안 알고리즘(네트워크 송수신 데이터 암호화 rsa,des등),
      방화벽,중요데이터는 서버측에서 관리 등이 중요한 것임)

(ex) 자신이 생성된 시간을 기록해두는 빈 클래스

package ***;
import java.util.*;

public class CurrentTimeBean
{
  private int hours;
  private int minutes;

  public CurrentTimeBean()
  {
     Calendar now = Calendar.getInstance();
     this.hours = now.get(Calendar.HOUR_OF_DAY);
     this.minustes = now.get(Calendar.MINUTE);
   }

   public void setHours(int hours)
   {
      this.hours = hours;
   }
    
   public int getHours()
  {
     return this.hours
   }

public void setMinutes(int minutes)
   {
      this.minutes= minutes;
   }
    
   public int getMinutes()
  {
     return this.minutes;
   }

}

**********위 처럼 구현해 놓고************
<jsp:useBean id="time" class="CurrentTimeBean" />
<html> 
<body>
It is now <jsp:getProperty name="time" property="minutes" />
minutes past the hour.
</body>
</html>

=>물론 해당 빈의 모든 프로퍼티에 get,set 메서드를 제공해줄 필요는 없다.(읽기전용,쓰기전용,둘다혼용 따라서 구현)

=>프로퍼티 이름 지을때 소문자+낙타식으로 간다. xml에 대해선 어찌할 것인가? XML 보단 Xml이 일관성 있다.(첫자만 대문자)


*******************인덱스 프로퍼티를 정의하는 방법1**********************
1.전체 집합을 하나의 배열로 반환하는 겟,셋 메서드 구현 = 사용하는 사람이 알아서(스클립틀릿,태그) 전체 반복 작업을 해야한다.
2.인덱스 값을 받아서 해당 요소만 반환하는 겟,셋 메서드 구현 = 1에 비해 유용성이 높다.
3.전체 집합의 수를 돌려주는(length던지 size) 메서드 구현  
4.물론 특정 서비스(비지니스로직)를 제공한다면 해당 메서드도 구현해야 할것이다. (vo 클래스인지 따라)
5.아참.. 세터,게터로 일일히 jsp 페이지에서 세팅해야하니... init(String "intA,intB,intC")등의 메서드를 제공해도 좋을 것이다.
=> 1,2,3  +@로  제공하자 ^^//

=>인덱스 프로퍼티의 경우.. 안타깝게도 jsp 페이지 내부에 자바 코드(스클릿틀릿,표현식)을 사용해야 한다. 자바 코드를 지울수
  있는 수단은.. 짜잔~ "커스텀 태그"  <-- 얼렁 공부해야 할텐데...
  
 
(cf)jsp 표준 액션 태그의 경우.. 스탈라 프로퍼티만 다룰수 있다.(그럼으로 위의 5같은 메서드가 필요하다)

public void setNumbersList(String values)
{
  ArrayList<String> list = new ArrayList<String>();
  StringTokenizer tok = new StringTokenizer(values, ","); // ㅋㅋㅋ 내가 로또 클래스 문자열 매개변수로 처리할때 요거 썼지
  //일단 구분자로 잘라서 관리하고
  while(tok.hasNext())
  {
  list.add(tok.nextToken()); //매개변수 유효성 체크는 생략하나보다 ?
  }
  //구분자로 잘라낸 문자열들을 실제 사용할 타입으로 변환해서 저장
  numbers = new double[n.size()]; 
  for(int i=0; i<numbers.length; i++)
  {
  numbers[i] = Double.parseDouble( list.get(i) );
  }
}

public String getNumberList()
{
  String list = new String(); //스트링으로 반환하기 위한
  for( int i=0; i< numbers.length; i++)
  {
     if( i != numbers.length)
        list += numbers[i] + ","; // , , , col의 형식 만들어주기
     else 
       list += "" + numbers[i]; // row
   }
  return list;
}

=>jsp에서 사용시

<jsp;useBean id="stat" class="com.taglib.wdjsp.components.StatBean">
  <jsp:setProperty name="stat" property="numbersList" value="100,250,150,50,450" />
</jsp:useBean>

<html>
<body>
The average of <jsp:getProperty name="stat" property="numbersList" />
is eqaul to <jsp:getProperty name="stat" property="average" />
</body>
</html>

*******************인덱스 프로퍼티를 정의하는 방법2**********************
=> idea:인덱스에 대한 커서의 개념을 구현한다. JDBC의 ResultSet클래스 , JDBC2.0의 CachedRowSet 클래스
    즉 빈 클래스 안에 인덱스를 나타내는 인스턴스 변수를 넣고 이값을 증가,감소 시키는 것으로 인덱스 프로퍼티 액세스
    가능하게 하는것. (말 그대로 이터레이터 제공)

(ex) 
planets.jsp

<html>
<body bgcolor="white">
<jsp:useBean id="planet" class="wdjsp.PlanetBean" />
<table border="1"> //레이아웃 매니저를 떠올리면 될듯 (테이블 경계 1개 설정)
<tr> //테이블의 행(row)를 의미하는 듯
<th>Planet</th> //테이블의 열(col)을 세로(horizon)으로 표현한듯? <-- 헤더를 의미하는 키워드임.즉 테이블의 각 열의 대표이름
<th>Number of Moons</th>

<% while(planet.next() ) { %>  //이터레이터 처럼 반복자를 제공했긴 하지만, 스클립틀릿으로 자바코드 사용하는것은 유지보수
                                            //최악이다..나중에 커스텀 태그 쓰자! jsp:ForLoopList 같은걸로
<tr> //하나의 테이블 행에
<td> <jsp:getProperty name="planet" property="name" /></td>
<td align="center"> <jsp:getProperty name="planet" property="moons" /></td>
</tr>
<% } %>

</table>
</body>
</html>

=> 음.. html 문법에 대해 굳이 안찾아봐도 해석이 되고 있음...(happy)

PlanetBean.java

package wdjsp;

public class PlanetBean{
 private static final int numPlanets = 0;
 private static final String[] names = {
  "Mecury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus",
  "Neptune", "Pluto" };
 private static final int[] moons = {0,0,1,2,16,18,20,8,1};

private int index;

public PlanetBean(){
index = -1; //인덱스 초기 값
}

public void first(){
index = -1;
}

public boolean next(){
index++;
if(index >= numPlanets)
{
  index--;
  return false;
 }
else
{
  return true;
 }
}

public String getName(){
 return names[index];
}

public int getMoons(){
 return moons[index];
 }
}


*****jsp에서 프로퍼티의 타입이 전부 String 으로 넘어오는걸 기억할것!******

(1)primitive -> String
java.lang.Boolean.toString(boolean)
java.lang.Byte.toString(byte)
java.lang.Character.toString(char)
..
object = 객체의 toString() 호출   => 그럼으로 재정의가 필요함

(2)String -> primitive
java.lang.Boolean.valueOf(String);
java.lang.Integer.valueOf(String);
...
object의 경우 new String(String)   => 구현에 문제가 있다. 스트링에서 객체를 어떻게 구성할 것인가?
object = new object();
object.booleanA = Boolean.valueOf(String[0]);
object.intA = Integer.valueOf(String[1]);
... 식으로..

****매개변수의 유효성을 검증해주는 메서드 필요****
boolean isValidMyObject() 식으로

****아까 위에서 거론했지만.. 디폴트생성자가 기본임으로 디폴트생성자->매개변수생성자->init() 메서드 호출 필요***

(ex)
public A(){
 this(5)
}

public A(int a){
this.temp = temp;
init();
}

private void init(){
 maxTemp = this.temp + 10;
 ...
 if(maxTemp > 10)
    status = Status.Max;
 else
    status = Status.Normal;
}


****빈을 구현해본 자작 병신코드 OTL ***

package com.taglib.jsp.components;

import java.util.StringTokenizer;

//복리이자를 계산해주는 빈
// 복지 적용시 원금 계산
// 지불금액 = 원금* (1+이자율(요것도 연이율/기간))의 복리횟수(연도/기간)의제곱 (한마디로 등비 수열이었나??)
public class CompoundInterestBean  //아하하 implements Serializable 까먹음...
{
private double principal; //원금
private int years; //총기간
private int compound; //복지이자가 누적되는 단위기간
private double interestRate; //이자율
private double futureValue; //미래 금액
//타입이 달라서 컨테이너 보관이 안돼니.. 망할 ..ArrayList<Object> 로 처리할까 보다 -_-;
//1.디폴트 생성자
public CompoundInterestBean()
{
// super();
// this.principal = 0.d;
// this.years = 0;
// this.compound = 0;
// this.interestRate = 0.d;
// this.futureValue = 0.d;
this("1000.0,12,1,8.0"); //매개변수 있는 생성자 사용대신 super()를 사용 못하게됨 ㅠㅠ
}
//1.1매개변수 있는 생성자 (이놈 쓸라면 스클립틀릿 or 표현식 필요)
public CompoundInterestBean(String params)
{
//jvm 매개변수로 -ea 인가 필요
//assert init(params) == true : "CompoundInterestBean(String params)실패";
try
{
init(params);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//입력 처리용 내부 메서드 (이걸 public 으로 풀어줄 필요가 있을까??? 내부 작업용 메서드인데..private로 하는게?)
private void init(String params) throws Exception //익셉션 클래스 따로 만들기 귀찮!
{
// 1.,로 구분되어 있다고 가정한다. 
// 2.필요한 토큰은 5개 (타입이 int와 double로 다름으로 반복문 사용 안됨)
// 3.토크나이저를 사용한다.
// 1.예외처리 (throw나 throws 선언은 안하기~) 
if((params.length() > 0) && (" ".equals(params)) == false)
{
//2.잘라내기 위해 토크나이저 생성
StringTokenizer tk = new StringTokenizer(params,",");
//3.토큰 갯수 검사
if(tk.hasMoreTokens() && tk.countTokens() == 4) //상수 때려받아서 죄송
{
//4.각각의 매개변수의 범위를 체크한다.
Double principal = Double.valueOf(tk.nextToken());
if(!isValidPrincipal(principal))
throw new Exception();
int years = Integer.valueOf(tk.nextToken());
if(!isValidYear(years))
throw new Exception();
int compound = Integer.valueOf(tk.nextToken());
if(!isValidCompound(compound))
throw new Exception();
Double interestRate = Double.valueOf(tk.nextToken());
if(!isValidInterestRate(interestRate))
throw new Exception();
//5.순서대로 변환해서 가져온다.
this.principal = principal;
this.years = years;
this.compound = compound;
this.interestRate = interestRate;
//6.미래 이자 계산도 여기서 해야할까?
//this.futureValue = getFutureValue();
this.futureValue = 0.d;
}
else
{
throw new Exception();
}
}
}
//2.게터세터
public double getPrincipal() {
return principal;
}

public void setPrincipal(double principal) {
this.principal = principal;
}

public int getYears() {
return years;
}

public void setYears(int years) {
this.years = years;
}

public int getCompound() {
return compound;
}

public void setCompound(int compound) {
this.compound = compound;
}

public double getInterestRate() {
return interestRate;
}

public void setInterestRate(double interestRate) {
this.interestRate = interestRate;
}

public double getFutureValue() 
{
//계산해야 한다. 계산해서 futureValue 초기화해줄 내부 메서드 추가
calcutateFutureValue();
return futureValue;
}

// public void setFutureValue(double futureValue) {
// this.futureValue = futureValue;
// }
//3.toString 구현 (모든 프로퍼티를 ,로 붙여서)
public String toString()
{
// String retVal = new String("");
// //갯수가 적으니 StringBuffer나 Builder 안쓰고 String으로 처리
// retVal += this.principal + ',' + this.years + ',' + this.compound + ','
//  + this.interestRate + ',' + this.futureValue + ',';
// //아 코드 드럽다.
// return retVal;
return "" + this.principal + ',' + this.years + ',' + this.compound + ','
 + this.interestRate; //futureValue는 리턴값임으로 제외
}
//4.요 빈의 특별 서비스 메서드  복리 계산해서 토탈 금액 반환해주기
private void calcutateFutureValue()
{
this.futureValue = this.principal * Math.pow(1+ this.interestRate / this.compound,
this.years / this.compound);
}
//5.매개변수 프로퍼티의 유효성을 체크 (이것들도 private가 맞지만.. jsp에서 사용할지도 모르니;; public으로 열어놨다!
public boolean isValidPrincipal(double principal)
{
boolean retVal = true;
//원금은 음수,0 일수 없다. double 범위 체크는 안해도 될듯..
if(principal <= 0.d)
{
retVal = false;
}
return retVal;
}
public boolean isValidYear(int year)
{
boolean retVal = true;
//연도는 음수,0일수 없다. 마찬가지로 int 범위체크 불필요
if(year <= 0)
{
retVal = false;
}
return retVal;
}
public boolean isValidCompound(int compound)
{
boolean retVal = true;
//이자율 계산 기간의 경우.. 1이면 1달마다 2면 2달마다  12면 1년마다 
//그럼으로 음수,0만 체크하면 된다?
if(compound <= 0)
{
retVal = false;
}
return retVal;
}
public boolean isValidInterestRate(double interestRate)
{
boolean retVal = true;
//이자율이야 고리대금이면.. 엄청 클수 있으니까.. 
//음수,0 체크만
if(interestRate <= 0.d)
{
retVal = false;
}
return retVal;
}
}


******************BeanInfo 인터페이스의 존재의미**********

<pre>public interface BeanInfo</pre>

Bean 의 구현자는, 이 BeanInfo 인터페이스를 구현하는 BeanInfo 클래스를 제공해, 자신의 Bean 의 메소드, 프로퍼티, 이벤트 등에 관한 명시적인 정보를 제공할 수가 있습니다.

Bean 의 구현자는, 명시적인 정보를 모두 제공할 필요는 없습니다. 제공하는 정보를 선택할 수가 있어 나머지는 Bean 클래스의 메소드의 저레벨 리플렉션을 사용한 자동 해석 및 표준의 디자인 패턴의 적용에 의해 취득할 수 있습니다.

사용자는, 각 Descriptor 클래스의 일부로서 매우 많은 종류의 정보를 제공할 기회가 주어지게 됩니다. 그러나, 각 생성자 이 필요로 하는 최소한의 코어 정보를 제공하는 것만으로도 충분합니다.

BeanInfo 클래스의 편리한 「무조작」base class를 제공하는 SimpleBeanInfo 클래스도 참조해 주세요. 이것을 사용하면(자), 명시적인 정보를 제공하고 싶은 특정의 개소를 오버라이드(override) 할 수 있습니다.

Bean 의 모든 동작에 대해 알려면 Introspector 클래스를 참조해 주세요.


=>기존에 만들어둔 자바 클래스에 요 인터페이스를 구현하면.. jsp 컴포넌트 개발 가능



<pre>public class SimpleBeanInfo
extends Object
implements BeanInfo
</pre>

사용자가 BeanInfo 클래스를 제공하기 쉬워지도록(듯이) 하는 지원 클래스입니다.

무조작 (noop) 정보의 제공을 디폴트로 설정합니다. 또, 선택한 토픽에 대한보다 명시적인 정보를 제공하기 위해서, 선택적으로 오버라이드(override) 되는 일이 있습니다. 인트로스페크타는 "noop" 치를 검출하면(자), 저레벨의 인트로스페크션 및 설계 패턴을 적용해, 타겟 Bean 를 자동적으로 해석합니다.



*****Serializable 인터페이스 구현하기 필요*****

서버가 동작 멈출때 파일,디비등에 빈정보 기억했다가 로드하거나,

트래픽이 많은 환경에서의 클러스트링(db에 쿼리쏠때 연결되는 작업지시를 버퍼에 담아두는

것)을 지원하는 서버에서 필요하다.



******스클립틀릿과 빈 태그 함께 쓰기*******


<jsp:useBean id="xxx" class="xxxBean" scope="page" />

xxx xxxx <jsp:getProperty name="xxx" property="a" />

<jsp:useBean id="xxx" class="xxxBean" scope="page" />

xxx xxx <%= xxx.getA() %> 

는 동일하다.


=>주의할점: getA()를 통해 리턴되는 타입이 String인지 확신할 수 없다!!!!


'프로그래밍 > JSP' 카테고리의 다른 글

jsp ~ jdbc  (0) 2014.01.01
jsp에서 빈의 사용3  (0) 2014.01.01
빈을 이용한 컴포넌트 방식의 설계1  (0) 2014.01.01
jsp 스크립트  (0) 2014.01.01
part2(2013/11/27)  (0) 2014.01.01
by givingsheart 2014. 1. 1. 15:58