forked from spring-projects/spring-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjmx.xml
1642 lines (1328 loc) · 70.4 KB
/
jmx.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="jmx"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
<title>JMX</title>
<section xml:id="jmx-introduction">
<title>Introduction</title>
<para>The JMX support in Spring provides you with the features to easily
and transparently integrate your Spring application into a JMX
infrastructure.</para>
<sidebar>
<title>JMX?</title>
<para>This chapter is not an introduction to JMX... it doesn't try to
explain the motivations of why one might want to use JMX (or indeed what
the letters JMX actually stand for). If you are new to JMX, check out
<xref linkend="jmx-resources" /> at the end of this chapter.</para>
</sidebar>
<para>Specifically, Spring's JMX support provides four core
features:</para>
<itemizedlist>
<listitem>
<para>The automatic registration of <emphasis>any</emphasis> Spring
bean as a JMX MBean</para>
</listitem>
<listitem>
<para>A flexible mechanism for controlling the management interface of
your beans</para>
</listitem>
<listitem>
<para>The declarative exposure of MBeans over remote, JSR-160
connectors</para>
</listitem>
<listitem>
<para>The simple proxying of both local and remote MBean
resources</para>
</listitem>
</itemizedlist>
<para>These features are designed to work without coupling your
application components to either Spring or JMX interfaces and classes.
Indeed, for the most part your application classes need not be aware of
either Spring or JMX in order to take advantage of the Spring JMX
features.</para>
</section>
<section xml:id="jmx-exporting">
<title>Exporting your beans to JMX</title>
<para>The core class in Spring's JMX framework is the
<classname>MBeanExporter</classname>. This class is responsible for taking
your Spring beans and registering them with a JMX
<interfacename>MBeanServer</interfacename>. For example, consider the following
class:</para>
<programlisting language="java"><![CDATA[package org.springframework.jmx;
public class JmxTestBean implements IJmxTestBean {
private String name;
private int age;
private boolean isSuperman;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int add(int x, int y) {
return x + y;
}
public void dontExposeMe() {
throw new RuntimeException();
}
}]]></programlisting>
<para>To expose the properties and methods of this bean as attributes and
operations of an MBean you simply configure an instance of the
<classname>MBeanExporter</classname> class in your configuration file and
pass in the bean as shown below:</para>
<programlisting language="xml"><![CDATA[<beans>
]]><lineannotation><!-- this bean must not be lazily initialized if the exporting is to happen --></lineannotation><![CDATA[
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter"]]> <emphasis
role="bold">lazy-init="false"</emphasis><![CDATA[>
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>]]></programlisting>
<para>The pertinent bean definition from the above configuration snippet
is the <literal>exporter</literal> bean. The <literal>beans</literal>
property tells the <classname>MBeanExporter</classname> exactly which of
your beans must be exported to the JMX <interfacename>MBeanServer</interfacename>.
In the default configuration, the key of each entry in the
<literal>beans</literal> <interfacename>Map</interfacename> is used as the
<classname>ObjectName</classname> for the bean referenced by the
corresponding entry value. This behavior can be changed as described in
<xref linkend="jmx-naming"/>.</para>
<para>With this configuration the <literal>testBean</literal> bean is
exposed as an MBean under the <classname>ObjectName</classname>
<literal>bean:name=testBean1</literal>. By default, all
<emphasis>public</emphasis> properties of the bean are exposed as
attributes and all <emphasis>public</emphasis> methods (bar those
inherited from the <classname>Object</classname> class) are exposed as
operations.</para>
<section xml:id="jmx-exporting-mbeanserver">
<title>Creating an <interfacename>MBeanServer</interfacename></title>
<para>The above configuration assumes that the application is running in
an environment that has one (and only one)
<interfacename>MBeanServer</interfacename> already running. In this case, Spring
will attempt to locate the running <interfacename>MBeanServer</interfacename>
and register your beans with that server (if any). This behavior is
useful when your application is running inside a container such as
Tomcat or IBM WebSphere that has its own
<interfacename>MBeanServer</interfacename>.</para>
<para>However, this approach is of no use in a standalone environment,
or when running inside a container that does not provide an
<interfacename>MBeanServer</interfacename>. To address this you can create an
<interfacename>MBeanServer</interfacename> instance declaratively by adding an
instance of the
<classname>org.springframework.jmx.support.MBeanServerFactoryBean</classname>
class to your configuration. You can also ensure that a specific
<interfacename>MBeanServer</interfacename> is used by setting the value of the
<classname>MBeanExporter</classname>'s <literal>server</literal>
property to the <interfacename>MBeanServer</interfacename> value returned by an
<classname>MBeanServerFactoryBean</classname>; for example:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
]]><lineannotation><!--
this bean needs to be eagerly pre-instantiated in order for the exporting to occur;
this means that it must not be marked as lazily initialized
--></lineannotation><![CDATA[
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>]]></programlisting>
<para>Here an instance of <interfacename>MBeanServer</interfacename> is created
by the <classname>MBeanServerFactoryBean</classname> and is supplied to
the <classname>MBeanExporter</classname> via the server property. When
you supply your own <interfacename>MBeanServer</interfacename> instance, the
<classname>MBeanExporter</classname> will not attempt to locate a
running <interfacename>MBeanServer</interfacename> and will use the supplied
<interfacename>MBeanServer</interfacename> instance. For this to work correctly,
you must (of course) have a JMX implementation on your classpath.</para>
</section>
<section xml:id="jmx-mbean-server">
<title>Reusing an existing <interfacename>MBeanServer</interfacename></title>
<para>If no server is specified, the <classname>MBeanExporter</classname>
tries to automatically detect a running <interfacename>MBeanServer</interfacename>.
This works in most environment where only one
<interfacename>MBeanServer</interfacename> instance is used, however when multiple
instances exist, the exporter might pick the wrong server. In such
cases, one should use the <interfacename>MBeanServer</interfacename>
<literal>agentId</literal> to indicate which instance to be used:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
]]><lineannotation><!-- indicate to first look for a server --></lineannotation><![CDATA[
<property name="locateExistingServerIfPossible" value="true"/>
]]><lineannotation><!-- search for the MBeanServer instance with the given agentId --></lineannotation><![CDATA[
<property name="agentId" value="]]><emphasis><![CDATA[<MBeanServer instance agentId>]]></emphasis><![CDATA["/>
</bean>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
...
</bean>
</beans>]]></programlisting>
<para>For platforms/cases where the existing <interfacename>MBeanServer</interfacename>
has a dynamic (or unknown) <literal>agentId</literal> which is retrieved through lookup
methods, one should use <link linkend="beans-factory-class-static-factory-method">factory-method</link>:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
]]><lineannotation><!-- Custom MBeanServerLocator --></lineannotation><![CDATA[
<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
</property>
]]><lineannotation><!-- other beans here --></lineannotation><![CDATA[
</bean>
</beans>]]></programlisting>
</section>
<section xml:id="jmx-exporting-lazy">
<title>Lazy-initialized MBeans</title>
<para>If you configure a bean with the
<classname>MBeanExporter</classname> that is also configured for lazy
initialization, then the <classname>MBeanExporter</classname> will
<emphasis role="bold">not</emphasis> break this contract and will avoid
instantiating the bean. Instead, it will register a proxy with
the <interfacename>MBeanServer</interfacename> and will defer obtaining the bean
from the container until the first invocation on the proxy occurs.</para>
</section>
<section xml:id="jmx-exporting-auto">
<title>Automatic registration of MBeans</title>
<para>Any beans that are exported through the
<classname>MBeanExporter</classname> and are already valid MBeans are
registered as-is with the <interfacename>MBeanServer</interfacename> without
further intervention from Spring. MBeans can be automatically detected
by the <classname>MBeanExporter</classname> by setting the
<literal>autodetect</literal> property to <literal>true</literal>:</para>
<programlisting language="xml"><![CDATA[<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="autodetect" value="true"/>
</bean>
<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>]]></programlisting>
<para>Here, the bean called <literal>spring:mbean=true</literal> is
already a valid JMX MBean and will be automatically registered by
Spring. By default, beans that are autodetected for JMX registration
have their bean name used as the <classname>ObjectName</classname>. This
behavior can be overridden as detailed in <xref linkend="jmx-naming" />.</para>
</section>
<section xml:id="jmx-exporting-registration-behavior">
<title>Controlling the registration behavior</title>
<para>Consider the scenario where a Spring
<classname>MBeanExporter</classname> attempts to register an
<classname>MBean</classname> with an <interfacename>MBeanServer</interfacename>
using the <classname>ObjectName</classname>
<literal>'bean:name=testBean1'</literal>. If an
<classname>MBean</classname> instance has already been registered under
that same <classname>ObjectName</classname>, the default behavior is to
fail (and throw an
<exceptionname>InstanceAlreadyExistsException</exceptionname>).</para>
<para>It is possible to control the behavior of exactly what happens
when an <classname>MBean</classname> is registered with an
<interfacename>MBeanServer</interfacename>. Spring's JMX support allows for
three different registration behaviors to control the registration
behavior when the registration process finds that an
<classname>MBean</classname> has already been registered under the same
<classname>ObjectName</classname>; these registration behaviors are
summarized on the following table:</para>
<table xml:id="jmx-registration-behaviors">
<title>Registration Behaviors</title>
<tgroup cols="2">
<colspec align="left" />
<colspec colnum="1" colwidth="*" />
<colspec colnum="2" colwidth="*" />
<thead>
<row>
<entry align="center">Registration behavior</entry>
<entry align="center">Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry><para><literal>REGISTRATION_FAIL_ON_EXISTING</literal></para></entry>
<entry><para> This is the default registration behavior. If an
<classname>MBean</classname> instance has already been
registered under the same <classname>ObjectName</classname>,
the <classname>MBean</classname> that is being registered will
not be registered and an
<exceptionname>InstanceAlreadyExistsException</exceptionname> will be
thrown. The existing <classname>MBean</classname> is
unaffected. </para></entry>
</row>
<row>
<entry><para><literal>REGISTRATION_IGNORE_EXISTING</literal></para></entry>
<entry><para> If an <classname>MBean</classname> instance has
already been registered under the same
<classname>ObjectName</classname>, the
<classname>MBean</classname> that is being registered will
<emphasis>not</emphasis> be registered. The existing
<classname>MBean</classname> is unaffected, and no
<exceptionname>Exception</exceptionname> will be thrown. </para>
<para> This is useful in settings where multiple applications
want to share a common <classname>MBean</classname> in a
shared <interfacename>MBeanServer</interfacename>. </para></entry>
</row>
<row>
<entry><para><literal>REGISTRATION_REPLACE_EXISTING</literal></para></entry>
<entry><para> If an <classname>MBean</classname> instance has
already been registered under the same
<classname>ObjectName</classname>, the existing
<classname>MBean</classname> that was previously registered
will be unregistered and the new <classname>MBean</classname>
will be registered in its place (the new
<classname>MBean</classname> effectively replaces the previous
instance). </para></entry>
</row>
</tbody>
</tgroup>
</table>
<para>The above values are defined as constants on the
<classname>MBeanRegistrationSupport</classname> class (the
<classname>MBeanExporter</classname> class derives from this
superclass). If you want to change the default registration behavior,
you simply need to set the value of the
<literal>registrationBehaviorName</literal> property on your
<classname>MBeanExporter</classname> definition to one of those
values.</para>
<para>The following example illustrates how to effect a change from the
default registration behavior to the
<literal>REGISTRATION_REPLACE_EXISTING</literal> behavior:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>]]></programlisting>
</section>
</section>
<section xml:id="jmx-interface">
<title>Controlling the management interface of your beans</title>
<para>In the previous example, you had little control over the management
interface of your bean; <emphasis>all</emphasis> of the
<emphasis>public</emphasis> properties and methods of each exported bean
was exposed as JMX attributes and operations respectively. To exercise
finer-grained control over exactly which properties and methods of your
exported beans are actually exposed as JMX attributes and operations,
Spring JMX provides a comprehensive and extensible mechanism for
controlling the management interfaces of your beans.</para>
<section xml:id="jmx-interface-assembler">
<title>The <interfacename>MBeanInfoAssembler</interfacename>
Interface</title>
<para>Behind the scenes, the <classname>MBeanExporter</classname>
delegates to an implementation of the
<classname>org.springframework.jmx.export.assembler.MBeanInfoAssembler</classname>
interface which is responsible for defining the management interface of
each bean that is being exposed. The default implementation,
<classname>org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler</classname>,
simply defines a management interface that exposes all public properties
and methods (as you saw in the previous examples). Spring provides two
additional implementations of the
<interfacename>MBeanInfoAssembler</interfacename> interface that allow
you to control the generated management interface using either
source-level metadata or any arbitrary interface.</para>
</section>
<section xml:id="jmx-interface-metadata">
<title>Using Source-Level Metadata (JDK 5.0 annotations)</title>
<para>Using the <classname>MetadataMBeanInfoAssembler</classname> you
can define the management interfaces for your beans using source level
metadata. The reading of metadata is encapsulated by the
<classname>org.springframework.jmx.export.metadata.JmxAttributeSource</classname>
interface. Spring JMX provides a default implementation which uses JDK 5.0 annotations, namely
<classname>org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource</classname>. The
<classname>MetadataMBeanInfoAssembler</classname>
<emphasis>must</emphasis> be configured with an implementation instance
of the <classname>JmxAttributeSource</classname> interface for it to
function correctly (there is <emphasis>no</emphasis> default).</para>
<para>To mark a bean for export to JMX, you should annotate the bean
class with the <classname>ManagedResource</classname> annotation. Each
method you wish to expose as an operation must be marked with the
<classname>ManagedOperation</classname> annotation and each property you
wish to expose must be marked with the
<classname>ManagedAttribute</classname> annotation. When marking
properties you can omit either the annotation of the getter or the
setter to create a write-only or read-only attribute
respectively.</para>
<para>The example below shows the annotated version of the
<classname>JmxTestBean</classname> class that you saw earlier:</para>
<programlisting language="java"><![CDATA[package org.springframework.jmx;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedAttribute;
@ManagedResource(objectName="bean:name=testBean4", description="My Managed Bean", log=true,
logFile="jmx.log", currencyTimeLimit=15, persistPolicy="OnUpdate", persistPeriod=200,
persistLocation="foo", persistName="bar")
public class AnnotationTestBean implements IJmxTestBean {
private String name;
private int age;
@ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15)
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@ManagedAttribute(description="The Name Attribute",
currencyTimeLimit=20,
defaultValue="bar",
persistPolicy="OnUpdate")
public void setName(String name) {
this.name = name;
}
@ManagedAttribute(defaultValue="foo", persistPeriod=300)
public String getName() {
return name;
}
@ManagedOperation(description="Add two numbers")
@ManagedOperationParameters({
@ManagedOperationParameter(name = "x", description = "The first number"),
@ManagedOperationParameter(name = "y", description = "The second number")})
public int add(int x, int y) {
return x + y;
}
public void dontExposeMe() {
throw new RuntimeException();
}
}]]></programlisting>
<para>Here you can see that the <classname>JmxTestBean</classname> class
is marked with the <classname>ManagedResource</classname> annotation and
that this <classname>ManagedResource</classname> annotation is configured
with a set of properties. These properties can be used to configure
various aspects of the MBean that is generated by the
<classname>MBeanExporter</classname>, and are explained in greater
detail later in section entitled <xref
linkend="jmx-interface-metadata-types" />.</para>
<para>You will also notice that both the <literal>age</literal> and
<literal>name</literal> properties are annotated with the
<classname>ManagedAttribute</classname> annotation, but in the case of
the <literal>age</literal> property, only the getter is marked. This
will cause both of these properties to be included in the management
interface as attributes, but the <literal>age</literal> attribute will
be read-only.</para>
<para>Finally, you will notice that the <literal>add(int, int)</literal>
method is marked with the <classname>ManagedOperation</classname>
attribute whereas the <literal>dontExposeMe()</literal> method is not.
This will cause the management interface to contain only one operation,
<literal>add(int, int)</literal>, when using the
<classname>MetadataMBeanInfoAssembler</classname>.</para>
<para>The configuration below shows how you configure the
<classname>MBeanExporter</classname> to use the
<classname>MetadataMBeanInfoAssembler</classname>:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
</bean>
<bean id="jmxAttributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
]]><lineannotation><!-- will create management interface using annotation metadata --></lineannotation><![CDATA[
<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
]]><lineannotation><!-- will pick up the ObjectName from the annotation --></lineannotation><![CDATA[
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.AnnotationTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>]]></programlisting>
<para>Here you can see that an
<classname>MetadataMBeanInfoAssembler</classname> bean has been
configured with an instance of the
<classname>AnnotationJmxAttributeSource</classname> class and passed to
the <classname>MBeanExporter</classname> through the assembler property.
This is all that is required to take advantage of metadata-driven
management interfaces for your Spring-exposed MBeans.</para>
</section>
<section xml:id="jmx-interface-metadata-types">
<title>Source-Level Metadata Types</title>
<para>The following source level metadata types are available for use in
Spring JMX:</para>
<para><table xml:id="jmx-metadata-types">
<title>Source-Level Metadata Types</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colname="spycolgen1" colnum="1" colwidth="*" />
<colspec colname="spycolgen2" colnum="2" colwidth="*" />
<thead>
<row>
<entry align="center">Purpose</entry>
<entry align="center">Annotation</entry>
<entry align="center">Annotation Type</entry>
</row>
</thead>
<tbody>
<row>
<entry>Mark all instances of a <classname>Class</classname> as
JMX managed resources</entry>
<entry><literal>@ManagedResource</literal></entry>
<entry>Class</entry>
</row>
<row>
<entry>Mark a method as a JMX operation</entry>
<entry><literal>@ManagedOperation</literal></entry>
<entry>Method</entry>
</row>
<row>
<entry>Mark a getter or setter as one half of a JMX
attribute</entry>
<entry><classname>@ManagedAttribute</classname></entry>
<entry>Method (only getters and setters)</entry>
</row>
<row>
<entry>Define descriptions for operation parameters</entry>
<entry><classname>@ManagedOperationParameter</classname> and
<classname>@ManagedOperationParameters</classname></entry>
<entry>Method</entry>
</row>
</tbody>
</tgroup>
</table></para>
<para>The following configuration parameters are available for use on
these source-level metadata types:</para>
<para><table xml:id="jmx-metadata-parameters">
<title>Source-Level Metadata Parameters</title>
<tgroup cols="3">
<colspec align="left" />
<colspec colname="spycolgen1" colnum="1" colwidth="*" />
<colspec colname="spycolgen2" colnum="2" colwidth="*" />
<thead>
<row>
<entry align="center">Parameter</entry>
<entry align="center">Description</entry>
<entry align="center">Applies to</entry>
</row>
</thead>
<tbody>
<row>
<entry><classname>ObjectName</classname></entry>
<entry>Used by <classname>MetadataNamingStrategy</classname>
to determine the <classname>ObjectName</classname> of a
managed resource</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>description</literal></entry>
<entry>Sets the friendly description of the resource,
attribute or operation</entry>
<entry><classname>ManagedResource</classname>,
<classname>ManagedAttribute</classname>,
<classname>ManagedOperation</classname>,
<classname>ManagedOperationParameter</classname></entry>
</row>
<row>
<entry><literal>currencyTimeLimit</literal></entry>
<entry>Sets the value of the
<literal>currencyTimeLimit</literal> descriptor field</entry>
<entry><classname>ManagedResource</classname>,
<classname>ManagedAttribute</classname></entry>
</row>
<row>
<entry><literal>defaultValue</literal></entry>
<entry>Sets the value of the <literal>defaultValue</literal>
descriptor field</entry>
<entry><classname>ManagedAttribute</classname></entry>
</row>
<row>
<entry><literal>log</literal></entry>
<entry>Sets the value of the <literal>log</literal> descriptor
field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>logFile</literal></entry>
<entry>Sets the value of the <literal>logFile</literal>
descriptor field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>persistPolicy</literal></entry>
<entry>Sets the value of the <literal>persistPolicy</literal>
descriptor field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>persistPeriod</literal></entry>
<entry>Sets the value of the <literal>persistPeriod</literal>
descriptor field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>persistLocation</literal></entry>
<entry>Sets the value of the
<literal>persistLocation</literal> descriptor field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>persistName</literal></entry>
<entry>Sets the value of the <literal>persistName</literal>
descriptor field</entry>
<entry><classname>ManagedResource</classname></entry>
</row>
<row>
<entry><literal>name</literal></entry>
<entry>Sets the display name of an operation parameter</entry>
<entry><literal>ManagedOperationParameter</literal></entry>
</row>
<row>
<entry><literal>index</literal></entry>
<entry>Sets the index of an operation parameter</entry>
<entry><literal>ManagedOperationParameter</literal></entry>
</row>
</tbody>
</tgroup>
</table></para>
</section>
<section xml:id="jmx-interface-autodetect">
<title>The <classname>AutodetectCapableMBeanInfoAssembler</classname>
interface</title>
<para>To simplify configuration even further, Spring introduces the
<classname>AutodetectCapableMBeanInfoAssembler</classname> interface
which extends the <interfacename>MBeanInfoAssembler</interfacename>
interface to add support for autodetection of MBean resources. If you
configure the <classname>MBeanExporter</classname> with an instance of
<classname>AutodetectCapableMBeanInfoAssembler</classname> then it is
allowed to "vote" on the inclusion of beans for exposure to JMX.</para>
<para>Out of the box, the only implementation of the
<classname>AutodetectCapableMBeanInfo</classname> interface is the
<classname>MetadataMBeanInfoAssembler</classname> which will vote to
include any bean which is marked with the
<classname>ManagedResource</classname> attribute. The default approach
in this case is to use the bean name as the
<classname>ObjectName</classname> which results in a configuration like
this:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
]]><lineannotation><!-- notice how no 'beans' are explicitly configured here --></lineannotation><![CDATA[
<property name="autodetect" value="true"/>
<property name="assembler" ref="assembler"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource">
<bean class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
</property>
</bean>
</beans>]]></programlisting>
<para>Notice that in this configuration no beans are passed to the
<classname>MBeanExporter</classname>; however, the
<classname>JmxTestBean</classname> will still be registered since it is
marked with the <classname>ManagedResource</classname> attribute and the
<classname>MetadataMBeanInfoAssembler</classname> detects this and votes
to include it. The only problem with this approach is that the name of
the <classname>JmxTestBean</classname> now has business meaning. You can
address this issue by changing the default behavior for
<classname>ObjectName</classname> creation as defined in
<xref linkend="jmx-naming" />.</para>
</section>
<section xml:id="jmx-interface-java">
<title>Defining management interfaces using Java interfaces</title>
<para>In addition to the
<classname>MetadataMBeanInfoAssembler</classname>, Spring also includes
the <classname>InterfaceBasedMBeanInfoAssembler</classname> which allows
you to constrain the methods and properties that are exposed based on
the set of methods defined in a collection of interfaces.</para>
<para>Although the standard mechanism for exposing MBeans is to use
interfaces and a simple naming scheme, the
<classname>InterfaceBasedMBeanInfoAssembler</classname> extends this
functionality by removing the need for naming conventions, allowing you
to use more than one interface and removing the need for your beans to
implement the MBean interfaces.</para>
<para>Consider this interface that is used to define a management
interface for the <classname>JmxTestBean</classname> class that you saw
earlier:</para>
<programlisting language="java"><![CDATA[public interface IJmxTestBean {
public int add(int x, int y);
public long myOperation();
public int getAge();
public void setAge(int age);
public void setName(String name);
public String getName();
}]]></programlisting>
<para>This interface defines the methods and properties that will be
exposed as operations and attributes on the JMX MBean. The code below
shows how to configure Spring JMX to use this interface as the
definition for the management interface:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean5" value-ref="testBean"/>
</map>
</property>
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="managedInterfaces">
<value>org.springframework.jmx.IJmxTestBean</value>
</property>
</bean>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>]]></programlisting>
<para>Here you can see that the
<classname>InterfaceBasedMBeanInfoAssembler</classname> is configured to
use the <interfacename>IJmxTestBean</interfacename> interface when
constructing the management interface for any bean. It is important to
understand that beans processed by the
<classname>InterfaceBasedMBeanInfoAssembler</classname> are
<emphasis>not</emphasis> required to implement the interface used to
generate the JMX management interface.</para>
<para>In the case above, the <interfacename>IJmxTestBean</interfacename>
interface is used to construct all management interfaces for all beans.
In many cases this is not the desired behavior and you may want to use
different interfaces for different beans. In this case, you can pass
<classname>InterfaceBasedMBeanInfoAssembler</classname> a
<classname>Properties</classname> instance via the
<literal>interfaceMappings</literal> property, where the key of each
entry is the bean name and the value of each entry is a comma-separated
list of interface names to use for that bean.</para>
<para>If no management interface is specified through either the
<literal>managedInterfaces</literal> or
<literal>interfaceMappings</literal> properties, then the
<classname>InterfaceBasedMBeanInfoAssembler</classname> will reflect on
the bean and use all of the interfaces implemented by that bean to
create the management interface.</para>
</section>
<section xml:id="jmx-interface-methodnames">
<title>Using
<classname>MethodNameBasedMBeanInfoAssembler</classname></title>
<para>The <classname>MethodNameBasedMBeanInfoAssembler</classname>
allows you to specify a list of method names that will be exposed to JMX
as attributes and operations. The code below shows a sample
configuration for this:</para>
<programlisting language="xml"><![CDATA[<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean5" value-ref="testBean"/>
</map>
</property>
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
<property name="managedMethods">
<value>add,myOperation,getName,setName,getAge</value>
</property>
</bean>
</property>
</bean>]]></programlisting>
<para>Here you can see that the methods <literal>add</literal> and
<literal>myOperation</literal> will be exposed as JMX operations and
<literal>getName()</literal>, <literal>setName(String)</literal> and
<literal>getAge()</literal> will be exposed as the appropriate half of a
JMX attribute. In the code above, the method mappings apply to beans
that are exposed to JMX. To control method exposure on a bean-by-bean
basis, use the <literal>methodMappings</literal> property of
<classname>MethodNameMBeanInfoAssembler</classname> to map bean names to
lists of method names.</para>
</section>
</section>
<section xml:id="jmx-naming">
<title>Controlling the <classname>ObjectName</classname>s for your beans</title>
<para>Behind the scenes, the <classname>MBeanExporter</classname>
delegates to an implementation of the
<classname>ObjectNamingStrategy</classname> to obtain
<classname>ObjectName</classname>s for each of the beans it is
registering. The default implementation,
<classname>KeyNamingStrategy</classname>, will, by default, use the key of
the <literal>beans</literal> <interfacename>Map</interfacename> as the
<classname>ObjectName</classname>. In addition, the
<classname>KeyNamingStrategy</classname> can map the key of the
<literal>beans</literal> <interfacename>Map</interfacename> to an entry in a
<classname>Properties</classname> file (or files) to resolve the
<classname>ObjectName</classname>. In addition to the
<classname>KeyNamingStrategy</classname>, Spring provides two additional
<classname>ObjectNamingStrategy</classname> implementations: the
<classname>IdentityNamingStrategy</classname> that builds an
<classname>ObjectName</classname> based on the JVM identity of the bean
and the <classname>MetadataNamingStrategy</classname> that uses source
level metadata to obtain the <classname>ObjectName</classname>.</para>
<section xml:id="jmx-naming-properties">
<title>Reading <classname>ObjectName</classname>s from <classname>Properties</classname></title>
<para>You can configure your own
<classname>KeyNamingStrategy</classname> instance and configure it to
read <classname>ObjectName</classname>s from a
<classname>Properties</classname> instance rather than use bean key. The
<classname>KeyNamingStrategy</classname> will attempt to locate an entry
in the <classname>Properties</classname> with a key corresponding to the
bean key. If no entry is found or if the
<classname>Properties</classname> instance is <literal>null</literal>
then the bean key itself is used.</para>
<para>The code below shows a sample configuration for the
<classname>KeyNamingStrategy</classname>:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="testBean" value-ref="testBean"/>
</map>
</property>
<property name="namingStrategy" ref="namingStrategy"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">