JMX

์Šคํ”„๋ง์˜ DI๋Š” ๋นˆ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋‹จ ๋ฐฐํฌ๊ฐ€ ๋ผ์„œ ์‹คํ–‰์ค‘์ด๋ฉด, DI๋งŒ์œผ๋กœ๋Š” ์„ค์ •์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.

* ์ด ๋•Œ ์‹คํ–‰์ค‘์ธ ์•ฑ์˜ ์„ค์ •์„ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด, JMX(Java Management Extenstison)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ด€๋ฆฌ๋นˆ(Management Bean, ์ดํ•˜ MBean) : JMX๋ฅผ ์ด์šฉํ•œ ๊ด€๋ฆฌ ๋ชฉ์ ์— ํŠนํ™”๋˜์–ด ์žˆ๋Š” ๊ตฌ์„ฑ์š”์†Œ. ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ์ž๋ฐ” ๋นˆ => ๋„ค๊ฐ€์ง€ ํƒ€์ž…์˜ MBean์ด ์ •์˜

  • ํ‘œ์ค€ MBean : ๊ณ ์ •๋œ ์ž๋ฐ” ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฆฌํ”Œ๋ ‰์…˜์— ์˜ํ•ด ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€, ๊ฒฐ์ •๋˜๋Š” MBean

  • ๋™์  MBean : ์‹คํ–‰์‹œ์— DynamicMBean ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์— ์˜ํ•ด ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๊ฒฐ์ •, ์‹คํ–‰์‹œ๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ

  • ์˜คํ”ˆ MBean : ํŠน๋ณ„ํ•œ ๋™์ MBean์œผ๋กœ, ์• ํŠธ๋ฆฌ๋ทฐํŠธ์™€ ์˜คํผ๋ ˆ์ด์…˜์ด ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…, ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ํƒ€์ž…์šฉ ํด๋ž˜์Šค ๋ž˜ํผ, ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋‚˜ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋“œ ๋ž˜ํผ๋กœ ๋ถ„ํ•ด๋  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์œผ๋กœ ์ œํ•œ

  • ๋ชจ๋ธ MBean : ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ด€๋ฆฌ ๋ฆฌ์†Œ์Šค๋กœ ๋„˜๊ธฐ๋Š” ํŠน์ดํ•œ ๋™์ MBean. ์„ ์–ธ๋˜๋Š”๋งŒํผ ์ž‘์„ฑ๋˜์ง€๋Š” ์•Š์Œ. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์กฐ๋ฆฝํ•˜๋Š” ํŒฉํ† ๋ฆฌ์— ์˜ํ•ด ๋งŒ๋“ค์–ด์ง

=> ์Šคํ”„๋ง์˜ JMX ๋ชจ๋“ˆ์„ ์ด์šฉํ•˜์—ฌ, ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋นˆ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค


1 ์Šคํ”„๋ง ๋นˆ์„ MBean์œผ๋กœ ์ต์ŠคํฌํŠธํ•˜๊ธฐ

JMX๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€

public static final int DEFAULT_SPITTLES_PER_PAGE = 25; // ์‹คํ–‰์‹œ์ ์— ๋ณ€๊ฒฝํ•  ํ”„๋กœํผํ‹ฐ
private int spittlesPerPage = DEFAULT_SPITTLES_PER_PAGE; 

public void setSpittlesPerPage(int spittlesPerPage) { // ๋นŒ๋“œ ์‹œ์ ์— JMX๋ฅผ ์ด์šฉํ•˜์—ฌ ์‹คํ–‰ํ•  ๋ฉ”์†Œ๋“œ
  this.spittlesPerPage = spittlesPerPage;
}

public int getSpittlesPerPage() {
  return spittlesPerPage;
}

=> ์ด๊ฒƒ๋งŒ์œผ๋กœ, ์™ธ๋ถ€์—์„œ ์„ค์ •์€ ๋ถˆ๊ฐ€๋Šฅ, ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋นˆ์˜ ํ”„๋กœํผํ‹ฐ์ผ ๋ฟ

=> Controller ๋นˆ์„, MBean์œผ๋กœ ๋…ธ์ถœํ•ด์•ผ ํ•จ => ๊ทธ๋Ÿฌ๋ฉด ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ด€๋ฆฌ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ๋…ธ์ถœ

// MBeanExporter๋กœ, MBean ์„œ๋ฒ„์—์„œ ์Šคํ”„๋ง ๊ด€๋ฆฌ ๋นˆ์„, ๋ชจ๋ธMBean์œผ๋กœ ์ต์ŠคํฌํŠธ
@Bean
public MBeanExporter mbeanExporter(SpittleController spittleController) {
  MBeanExporter exporter = new MBeanExporter();
  Map<String, Object> beans = new HashMap<String, Object>();
  beans.put("spitter:name=SpittleController", spittleController); // Cotroller๋ฅผ, MBean์œผ๋กœ ๋…ธ์ถœ
  exporter.setBeans(beans);
  return exporter;
}

==> ์ด ๊ฒฝ์šฐ์˜ MBean - pair.spitter:name=SpittleController

=> MBeanExporter ์„ค์ • ํ›„, SpittleController๊ฐ€ ๊ด€๋ฆฌ ์„œ๋ฒ„์— ๋ชจ๋ธMBean์œผ๋กœ ์ต์ŠคํฌํŠธ ๋จ. ๋ชจ๋“  public ๋ฉค๋ฒ„๋Š” MBean ์˜คํผ๋ ˆ์ด์…˜๊ณผ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ์ต์ŠคํฌํŠธ.

=> ํ•˜์ง€๋งŒ spittlesPerPage ํ”„๋กœํผํ‹ฐ ์„ค์ •์„ ์ œ์™ธํ•˜๊ณ ๋Š”, ๊ตณ์ด ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ๋ณผ ํ•„์š”๊ฐ€ ์—†๋‹ค(spittles, getSpittlesPerPage emd)

=> ์ด๋Ÿฌํ•œ MBean์˜ ์• ํŠธ๋ฆฌ๋ทฐํŠธ์™€ ์˜คํŽ˜๋ ˆ์ด์…˜ ์ œ์–ด๋ฅผ ์œ„ํ•œ ๋ช‡๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Œ

  • ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋…ธ์ถœ, ๋ฌด์‹œํ•˜๋Š” ๋นˆ ๋ฉ”์†Œ๋“œ ์„ ์–ธ

  • ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ๋…ธ์ถœ ๋ฉ”์†Œ๋“œ ์„ ํƒ

  • ๋นˆ์˜ ์• ๋„ˆํ…Œ์ด์…˜์„ ์ ์šฉํ•˜์—ฌ ๊ด€๋ฆฌ ์• ํŠธ๋ฆฌ๋ทฐํŠธ์™€ ์˜คํผ๋ ˆ์ด์…˜ ์ง€์ •


1.1 ์ด๋ฆ„์œผ๋กœ ๋ฉ”์†Œ๋“œ ๋…ธ์ถœ์‹œํ‚ค๊ธฐ

MBean ์ธํฌ ์–ด์…ˆ๋ธ”๋Ÿฌ : MBean์—์„œ ์ต์ŠคํฌํŠธ ์‹œํ‚ฌ ์˜คํผ๋ ˆ์ด์…˜๊ณผ, ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ œํ•œํ•˜๋Š”๋ฐ ํ•ต์‹ฌ์ ์ธ ์—ญํ• 

=> MethoodNameBasedMBeanInfoAssembler

์ž๋ฐ”๋นˆ ๊ทœ์น™์— ์˜ํ•ด, spittlesPerPage ํ”„๋กœํผํ‹ฐ๋Š” set~(์„ค์ •์ž), get~(์ ‘๊ทผ์ž)๋ฅผ ๊ฐ€์ง, MBean์˜ ๋…ธ์ถœ์„ ์ œํ•œํ•˜๊ธฐ์œ„ํ•ด, ์–ด์…ˆ๋ธ”๋Ÿฌ์—๊ฒŒ ์ธํ„ฐํŽ˜์ด์Šค์— ์žˆ๋Š”๋ฉ”์†Œ๋“œ๋งŒ ํฌํ•จํ•˜๋ผ๊ณ  ์•Œ๋ ค์ฃผ์–ด์•ผ ํ•จ

// ์–ด์…ˆ๋ธ”๋Ÿฌ์—, ๊ด€๋ฆฌํ•  ๋ฉ”์†Œ๋“œ๋งŒ ๋“ฑ๋ก(set,get)
@Bean 
public MethodNameBasedMBeanInfoAssembler assembler() {
  MethodNameBasedMBeanInfoAssembler assembler = new MethodNameBasedMBeanInfoAssembler();
  assembler.setManagedMethods(new String[] {"getSpittlesPerPage", "setSpittlesPerPage" }); // ๊ด€๋ฆฌํ•  ๋ฉ”์†Œ๋“œ๋ฅผ ์„ ํƒ
  return assembler;
}


// ์ต์Šคํฌํ„ฐ์—, ํ•ด๋‹น ์–ด์…ˆ๋ธ”๋Ÿฌ ๋“ฑ๋ก
@Bean
public MBeanExporter mbeanExporter(SpittleController spittleController, MBeanInfoAssembler assembler) {
  MBeanExporter exporter = new MBeanExporter();
  Map<String, Object> beans = new HashMap<String, Object>();
  beans.put("spitter:name=SpittleController", spittleController);
  exporter.setBeans(beans);
  exporter.setAssembler(assembler); // ์–ด์…ˆ๋ธ”๋Ÿฌ ๋“ฑ๋ก
  return exporter;
}

=> ์œ„ ์‚ฌ์ง„์— ์žˆ๋˜ spittles()๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

* ๋˜ ๋‹ค๋ฅธ ๋ฉ”์†Œ๋“œ ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ์–ด์…ˆ๋ธ”๋Ÿฌ๋กœ๋Š”, MethodExclusionMBeanInfoAssembler๊ฐ€ ์žˆ์Œ

=> ์œ„์˜ MethodNamedBasedMBeanInfoAssembler์™€๋Š” ๋ฐ˜๋Œ€๋กœ, ๋“œ๋Ÿฌ๋‚ด์ง€ ์•Š๋Š” ๋ฉ”์†Œ๋“œ์˜ ๋ชฉ๋ก์„ ๋ถ€์—ฌํ•จ

@Bean
public MethodExclusionMBeanInfoAssembler assembler() {
  MethodExclusionMBeanInfoAssembler assembler = new MethodExclusionMBeanInfoAssembler();
  assembler.setIgnoredMethods(new String[] {"spittles"});
  
  return assembler;
}

* ๋™์ž‘์€ ์œ„์˜ ์‚ฌ์ง„๊ณผ ๊ฐ™๋‹ค(spittles๋ฅผ ์ œํ•œํ–ˆ๊ธฐ ๋•Œ๋ฌธ)


1.2 ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•œ MBean ์˜คํผ๋ ˆ์ด์…˜๊ณผ ์• ํŠธ๋ฆฌ๋ทฐํŠธ ์ •์˜

InrterfaceBasedMeanInfoAssembler๋Š”, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•ด MBean ๊ด€๋ฆฌ ์˜คํผ๋ ˆ์ด์…˜์œผ๋กœ ์ต์ŠคํฌํŠธํ•  ๋นˆ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์„ ํƒํ•˜๋Š” ์–ด์…ˆ๋ธ”๋Ÿฌ, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‚˜์—ดํ•œ๋‹ค๋Š” ์  ์ œ์™ธํ•˜๊ณ ๋Š” MethodNamedBasedMBeanInfoAssembler์™€ ์œ ์‚ฌํ•˜๋‹ค

// ์ธํ„ฐํŽ˜์ด์Šค
public interface SpittleControllerManagedOperations {
  int getSpittlesPerPage();
  void setSpittlesPerPage(int spittlesPerPage);
}

// ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์˜ ์–ด์…ˆ๋ธ”๋Ÿฌ => ์œ„์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ์„ค์ •
@Bean
public InterfaceBasedMBeanInfoAssembler assembler() {
  InterfaceBasedMBeanInfoAssembler assembler =  new InterfaceBasedMBeanInfoAssembler();
  assembler.setManagedInterfaces(new Class<?>[] { SpittleControllerManagedOperations.class });
  return assembler;
}

* ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ, MBean์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

* ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋ฉด, ์ˆ˜์‹ญ ๊ฐœ์˜ ๋ฉ”์†Œ๋“œ๋„ ๋ช‡ ๊ฐœ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ•ฉ์น  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ณต์ˆ˜์˜ MBean์„ ์ต์ŠคํฌํŠธํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์Šคํ”„๋ง ์„ค์ •์ด ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€๋œ๋‹ค

* ๊ทธ๋Ÿฌ๋‚˜, ๊ด€๋ฆฌ ์˜คํผ๋ ˆ์ด์…˜์˜ ์„ ์–ธ์€ ์ฝ”๋“œ์—์„œ ์ค‘๋ณต์œผ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค(๋‹จ์ˆœํžˆ MBeanExporter๋ฅผ ์œ„ํ•ด) => ์ด์™€ ๊ฐ™์€ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋Š ๊ฒƒ์ด ์ข‹๋‹ค


1.3 ์• ๋„ˆํ…Œ์ด์…˜ ์ฃผ๋„์˜ MBean์„ ์ด์šฉํ•œ ์ž‘์—…

MetadataMBeanIfoAssembler : ์• ๋„ˆํ…Œ์ด์…˜์„ ์ด์šฉํ•ด, ์˜คํผ๋ ˆ์ด์…˜๊ณผ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ธํฌ ์–ด์…ˆ๋ธ”๋Ÿฌ

=> ํ•ด๋‹น ์–ด์…ˆ๋ธ”๋Ÿฌ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์™€์ด์–ด๋ง ํ•˜๋Š” ์ž‘์—…์€ ๋ถ€๋‹ด์Šค๋Ÿฝ๊ณ , ๋‹จ์ง€ ์• ๋„ˆํ…Œ์ด์…˜์„ ์œ„ํ•ด ๊ทธ๋Ÿฐ ์ž‘์—…์„ ํ•  ํ•„์š”๊ฐ€ ์—†์Œ

=> ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ• ์ œ๊ณต, context ์„ค์ • ๋„ค์ž„์ŠคํŽ˜์ด์Šค์ด์šฉ(์‚ฌ์šฉํ•˜๋˜ MBeanExporter๋Œ€์‹ )

<context:mbean-export server="mbeanServer" />

=> ์ด์ œ ์Šคํ”„๋ง ๋นˆ์„ ๋ณ€ํ™˜, @ManagedResource๋ฅผ ์ ์šฉํ•˜๊ณ , ๋ฉ”์†Œ๋“œ๋Š” @ManagedOperation, @ManagedAttribute ์ ์šฉ

@Controller
@ManagedResource(objectName="spitter:name=SpittleController") // MBean์œผ๋กœ ์ต์ŠคํฌํŠธ
public class SpittleController {

  @ManagedAttribute  // ๊ด€๋ฆฌ ์• ํŠธ๋ฆฌ๋ทฐํŠธ
  public void setSpittlesPerPage(int spittlesPerPage) {
    this.spittlesPerPage = spittlesPerPage;
  }
  
  @ManagedAttribute // ๊ด€๋ฆฌ ์• ํŠธ๋ฆฌ๋ทฐํŠธ
  public int getSpittlesPerPage() {
    return spittlesPerPage;
  }
}

=> @ManagedAttribute๋ฅผ get์—๋‹ค๋งŒ ์ ์šฉํ•˜๋ฉด, JMX์—์„œ spittlePerPage๋Š” ์ฝ๊ธฐ์ „์šฉ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋จ

=> @ManagedAttribute๋ฅผ ์ ์šฉํ•˜๋ฉด, spittlePerPage ํ”„๋กœํผํ‹ฐ๋„, ๊ด€๋ฆฌ ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋กœ ๋…ธ์ถœ์‹œํ‚ด => ๋งŒ์•ฝ ํ”„๋กœํผํ‹ฐ ์ž์ฒด(spittlesPerPage)๋ฅผ ๋…ธ์ถœ์‹œํ‚ค๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด, @ManagedOPeration ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค


1.4 MBean ์ถฉ๋Œ ์ฒ˜๋ฆฌ

* ๋งŒ์•ฝ ๊ฐ™์€ ์ด๋ฆ„์˜ MBean์ด ์ด๋ฏธ ์กด์žฌํ•˜์—ฌ, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ? => ๊ธฐ๋ณธ์ ์œผ๋กœ, MBeanExporter๋Š” InstanceAlreadyExistException์„ ๋˜์ง

=> ํ•˜์ง€๋งŒ, ์ต์Šคํฌํ„ฐ์˜ registrationBehaviorName ํ”„๋กœํผํ‹ฐ๋‚˜, <contex:mbean=export>์˜ registration ์• ํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ด์šฉํ•˜์—ฌ, ์ถฉ๋Œ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค

@Bean
public MBeanExporter mbeanExporter(SpittleController spittleController, MBeanInfoAssembler assembler) {
  MBeanExporter exporter = new MBeanExporter();
  Map<String, Object> beans = new HashMap<String, Object>(); beans.put("spitter:name=SpittleController", spittleController); exporter.setBeans(beans);
  exporter.setAssembler(assembler); 
  exporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING); // ์ถฉ๋Œ์„ ๋ฌด์‹œํ•˜๊ณ , ์ƒˆ ๋นˆ์„ ๋“ฑ๋กํ•˜์ง€ ์•Š์Œ
  return exporter;
}
  • FAIL_ON_EXISTING : ์‹คํŒจ (default)

  • IGNORE_EXISTING : ์ถฉ๋Œ ๋ฌด์‹œํ•˜๊ณ , ์ƒˆ ๋นˆ ๋“ฑ๋กํ•˜์ง€ ์•Š์Œ

  • REPLACING_EXISTING : ๊ธฐ์กด ๋นˆ์„, ์ƒˆ๋กœ์šด ๋นˆ์œผ๋กœ ๋Œ€์ฒด


2. MBean ๋ฆฌ๋ชจํŒ…

์›๊ฒฉ JMX์˜ ํ‘œ์ค€์ด ํ•„์š”ํ•ด์ง€๋ฉฐ, JSR-160, ์ฆ‰ JMX ์›๊ฒฉ API ๋ช…์„ธ๊ฐ€ ๋งŒ๋“ค์–ด์ง. ์ตœ์†Œ RMI ๋ฐ”์ธ๋”ฉ์„ ํ•„์ˆ˜๋กœ ์š”๊ตฌํ•˜๋ฉฐ, ์„ ํƒ์ ์œผ๋กœ JMX ๋ฉ”์‹œ์ง• ํ”„๋กœํ† ์ฝœ(JMXMP)์„ ์š”๊ตฌ


2.1 ์›๊ฒฉ์œผ๋กœ MBean ๋…ธ์ถœํ•˜๊ธฐ

MBean์„ ์›๊ฒฉ ๊ฐ์ฒด๋กœ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด, ์Šคํ”„๋ง์˜ ConnectionServerFactoryBean ๊ตฌ์„ฑ

@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() {
  return new ConnectorServerFactoryBean();
}

ํ•ด๋‹น ํŒฉํ† ๋ฆฌ๋นˆ์€ JMXConnectorServer๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‹œ์ž‘ => 9875ํฌํŠธ -> service:jmx:jmxmp://localhost:9875

* JMX ๊ตฌํ˜„์ฒด์— ๋”ฐ๋ผ, RMI, SOAP, Hessian/Burlap, IIO๋ฅผ ํฌํ•จํ•˜์—ฌ, ๋ช‡ ๊ฐ€์ง€์˜ ์›๊ฒฉ ํ”„๋กœํ† ์ฝœ ์˜ต์…˜์ด ์กด์žฌ

==> RMI๋ฅผ ์ด์šฉํ•˜์—ฌ, MBean์„ ์ด์šฉํ•˜๊ธฐ

// serviceURL์„ RMI๋ฅผ ์‚ฌ์šฉ
@Bean
public ConnectorServerFactoryBean connectorServerFactoryBean() {
  ConnectorServerFactoryBean csfb = new ConnectorServerFactoryBean();
  csfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter"); // RMI ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ๋ฐ”์ธ๋”ฉ(1099)
  return csfb;
}

// RMI ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํŒฉํ† ๋ฆฌ ๋นˆ์„ ํ†ตํ•ด, MBean์ด์šฉ
@Bean
public RmiRegistryFactoryBean rmiRegistryFB() {
  RmiRegistryFactoryBean rmiRegistryFB = new RmiRegistryFactoryBean();
  rmiRegistryFB.setPort(1099);
  return rmiRegistryFB;
}

2.2 ์›๊ฒฉ MBean์— ์•ก์„ธ์Šค

์›๊ฒฉ MBean์„œ๋ฒ„์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด, MBeanServerConnectionFactoryBean์„ ์„ค์ •ํ•ด์•ผ ํ•จ

// ์œ„์—์„œ ๋งŒ๋“  rmi ์„œ๋ฒ„์— ์•ก์„ธ์Šคํ•˜๋Š”, ํŒฉํ† ๋ฆฌ๋นˆ ์„ ์–ธ
@Bean
public MBeanServerConnectionFactoryBean connectionFactoryBean() {
  MBeanServerConnectionFactoryBean mbscfb = new MBeanServerConnectionFactoryBean();
  mbscfb.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/spitter");
  return mbscfb;
}

// ๋‹ค ๋นˆ๊ณผ  ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ๋นˆ ํ”„๋กœํผํ‹ฐ๋กœ ์—ฐ๊ฒฐ
@Bean
public JmxClient jmxClient(MBeanServerConnection connection) {
  JmxClient jmxClient = new JmxClient();
  jmxClient.setMbeanServerConnection(connection);
  return jmxClient;
}

* MBeanServerConnection์—์„œ๋Š” ์›๊ฒฉ MBean ์„œ๋ฒ„๋ฅผ ์ฟผ๋ฆฌํ•˜๋ฉฐ, ํฌํ•จ๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฉ”์†Œ๋“œ๊ฐ€ ํฌํ•จ๋จ

// MBean์˜ ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์†Œ๋“œ
int mbeanCount = mbeanServerConnection.getMBeanCount

// ์›๊ฒฉ์„œ๋ฒ„์— ๋ชจ๋“  MBean์˜ ์ด๋ฆ„์„ ์ฟผ๋ฆฌํ•จ
java.util.Set mbeanNames = mbeanServerConnection.queryNames(null, null);

// ์ด ์™ธ์—๋„, MBean ์• ํŠธ๋ฆฌ๋ทฐํŠธ์— ์•ก์„ธ์Šค๋„ ๊ฐ€๋Šฅ(getAttribute)
String cronExpression = mbeanServerConnection.getAttribute(new ObjectName("spitter:name=SpittleController"), "spittlesPerPage");

// ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ’ ๋ณ€๊ฒฝ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค(setAttribute)
mbeanServerConnection.setAttribute(new ObjectName("spitter:name=SpittleController"), new Attribute("spittlesPerPage", 10));

// ์˜คํผ๋ ˆ์ด์…˜์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ(invoke), setSpittlesPerPage ์‚ฌ์šฉ
mbeanServerConnection.invoke(
    new ObjectName("spitter:name=SpittleController"),
    "setSpittlesPerPage",
    new Object[] { 100 },
    new String[] {"int"}
 );

=> invoke() ๋ฉ”์†Œ๋“œ์˜ ๊ฒฝ์šฐ, ์ผ์ผ์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ค˜์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ์ ์€ ์ผ๋ฐ˜์ ์ธ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋งŒํผ ์ง๊ด€์ ์ด์ง€ ์•Š๋‹ค

=> ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ฌ


2.3 MBean ํ”„๋ก์‹œ ๋งŒ๋“ค๊ธฐ

MBeanProxyFactoryBean : 15์žฅ์˜ ๋ฆฌ๋ชจํŒ… ํ”„๋ก์‹œ ๋นˆ๋“ค๊ณผ ๊ฐ™์€ ์„ฑ์งˆ์˜ ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ ๋นˆ

// ์•ž์—์„œ ๊ตฌํ˜„ํ•œ ์ ์ด ์žˆ๋Š”, SpittleControllerManagedOperations ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ”„๋ก์‹œ๋กœ ์ด์šฉ
@Bean
public MBeanProxyFactoryBean remoteSpittleControllerMBean(MBeanServerConnection mbeanServerClient) {
  MBeanProxyFactoryBean proxy = new MBeanProxyFactoryBean();
  proxy.setObjectName("");
  proxy.setServer(mbeanServerClient);
  proxy.setProxyInterface(SpittleControllerManagedOperations.class);
  return proxy;
}

3. ํ†ต์ง€์ฒ˜๋ฆฌ

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ค‘์š”ํ•œ ์ด๋ฒคํŠธ๋ฅผ ํŒŒ์•… ํ›„, ํ†ต์ง€๋ฅผ ํ•˜๊ธฐ์œ„ํ•ด ์Šคํ”„๋ง์˜ NotificicationPublisherAware ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ†ต์ง€ ์ „์†ก์„ ํ•  ์ˆ˜ ์žˆ์Œ

=> ์ผ๋‹จ, ์ „์†กํ•˜๊ณ ์ž ํ•˜๋Š” MBean์„ ๋ชจ๋‘ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•จ

@Component 
@ManagedResource("spitter:name=SpitterNotifier") 
@ManagedNotification(notificationTypes="SpittleNotifier.OneMillionSpittles", name="TODO")
public class SpittleNotifierImpl implements NotificationPublisherAware, SpittleNotifier { // ํผ๋ธ”๋ฆฌ์…”์–ด์›จ์–ด ๊ตฌํ˜„
  
  private NotificationPublisher notificationPublisher;
 
  public void setNotificationPublisher(NotificationPublisher notificationPublisher) { // ํผ๋ธ”๋ฆฌ์…” ์ฃผ์ž…
    this.notificationPublisher = notificationPublisher;
  }
  public void millionthSpittlePosted() { // ํ†ต์ง€ ์ „์†ก
    notificationPublisher.sendNotification(new Notification("SpittleNotifier.OneMillionSpittles", this, 0));
  }
}

* ์š”๊ตฌ๊ฐ€ ๋งŽ์€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ setNotificationPublisher๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋จ =>> ์ž๋™์ฃผ์ž…๋˜๋Š” NotificationPublisher๋ฅผ ์ด์šฉ

* setNotification() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ ๋˜๋ฉด, ํ†ต์ง€๊ฐ€ ์–ด๋””๋ก ๊ฐ€ ๊ฐ€๊ณ  ์žˆ๋‹ค => ๋ฆฌ์Šค๋„ˆ๊ฐ€ ๋ฐ˜์‘ํ•˜๋„๋ก ์„ค์ •


3.1 ํ†ต์ง€ ๋“ฃ๊ธฐ

ํ†ต์ง€๋ฅผ ๋ฐ›๋Š”ํ‘œ์ค€ ๋ฐฉ์‹์€ NotificationListener์˜ ๊ตฌํ˜„

public class PagingNotificationListener implements NotificationListener {
  public void handleNotification(Notification notification, Object handback) {
    ~~~~~        
  }
}

* PaginNotificationListener๋Š” ์ „ํ˜•์ ์ธ JMX ํ†ต์ง€ ๋ฆฌ์Šค๋„ˆ,. ํ†ต์ง€๋ฅผ ๋ฐ›์œผ๋ฉด ํ†ต์ง€์— ๋ฐ˜์‘ํ•˜๊ธฐ ์œ„ํ•ด handleNotification() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

* ์‹ค์ œ ๊ตฌํ˜„์€ ์ฑ…์— ์—†์Œ.. ์ฑ…๋„ ์ด์ œ ๊ท€์ฐฎ์€๋“ฏ

* ๋งˆ์ง€๋ง‰์œผ๋กœ MBeanExporter๋กœ ํ•ด๋‹น ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•œ๋‹ค

@Bean
public MBeanExporter mbeanExporter() {
  
  MBeanExporter exporter = new MBeanExporter();
  Map<?, NotificationListener> mappings =
  new HashMap<?, NotificationListener>();
  
  mappings.put("Spitter:name=PagingNotificationListener", new PagingNotificationListener());
  exporter.setNotificationListenerMappings(mappings);
  
  return exporter;
}

* notificationListenerMappings ํ”„๋กœํผํ‹ฐ๋Š” ํ†ต์ง€ ๋ฆฌ์Šค๋„ˆ๋ฅผ ํ•ด๋‹น MBean์— ๋งคํ•‘

Last updated