2015年10月7日星期三

4. Spring in Action -- Aspect-oriented Spring

1.  In software development, functions that span multiple points of an application are called cross-cutting concerns. Typically, these cross-cutting concerns are conceptually separate from (but often embedded directly within) the application’s business logic. Separating these cross-cutting concerns from the business logic is where aspect-oriented programming (AOP) goes to work.

2.  With AOP, you still define the common functionality in one place, but you can declaratively define how and where this functionality is applied without having to modify the class to which you’re applying the new feature. Cross-cutting concerns can now be modularized into special classes called aspects. This has two benefits. First, the logic for each concern is now in one place, as opposed to being scattered all over the code base. Second, our business modules are now cleaner since they only contain code for their primary concern (or core functionality) and secondary concerns have been moved to aspects.

3.  Aspects have a purpose—a job they’re meant to do. In AOP terms, the job of an aspect is called advice. An aspect’s functionality (advice) is woven into a program’s execution at one or more join points:

4.  In addition to describing the job that an aspect will perform, advice addresses the question of when to perform the job. Spring aspects can work with five kinds of advice:
  • Before—The advice functionality takes place before the advised method is invoked.
  • After—The advice functionality takes place after the advised method completes, regardless of the outcome.
  • After-returning—The advice functionality takes place after the advised method successfully completes.
  • After-throwing—The advice functionality takes place after the advised method throws an exception.
  • Around—The advice wraps the advised method, providing some functionality before and after the advised method is invoked.

5.  A join point is a point in the execution of the application where an aspect can be plugged in. This point could be a method being called, an exception being thrown, or even a field being modified. These are the points where your aspect’s code can be inserted into the normal flow of your application to add new behavior.

6.  An aspect doesn’t necessarily advise all join points in an application. Pointcuts help narrow down the join points advised by an aspect. If advice defines the what and when of aspects, then pointcuts define the where. A pointcut definition matches one or more join points at which advice should be woven. Often you specify these pointcuts using explicit class and method names or through regular expressions that define matching class and method name patterns. Some AOP frameworks allow you to create dynamic pointcuts that determine whether to apply advice based on runtime decisions, such as the value of method parameters.

7.  The join points are all the points within the execution flow of the application that are candidates to have advice applied. The pointcut defines where (at what join points) that advice is applied.

8.  An aspect is the merger of advice and pointcuts— what it does and where and when it does it.

9.  An introduction allows you to add new methods or attributes to existing classes. 

10.  Weaving is the process of applying aspects to a target object to create a new proxied object. The weaving can take place at several points in the target object’s lifetime:
  • Compile time—Aspects are woven in when the target class is compiled. This requires a special compiler. AspectJ’s weaving compiler weaves aspects this way.
  • Class load time—Aspects are woven in when the target class is loaded into the JVM. This requires a special ClassLoader that enhances that target class’s byte-code before the class is introduced into the application. AspectJ 5’s load-time weaving (LTW) support weaves aspects in this way.
  • Runtime—Aspects are woven in sometime during the execution of the application. Typically, an AOP container will dynamically generate a proxy object that will delegate to the target object while weaving in the aspects. This is how Spring AOP aspects are woven.

11.  AOP frameworks may differ in how rich their join point models are. Some allow you to apply advice at the field-modification level, whereas others only expose the join points related to method invocations. They may also differ in how and when they weave the aspects. Whatever the case, the ability to create pointcuts that define the join points at which aspects should be woven is what makes it an AOP framework.

12.  In 2005, the AspectWerkz project merged with AspectJ, marking the last significant activity in the AOP world and leaving us with three dominant AOP frameworks:
  • AspectJ (http://eclipse.org/aspectj)
  • JBoss AOP (http://www.jboss.org/jbossaop)
  • Spring AOP (http://www.springframework.org)

13.  Spring’s support for AOP comes in four flavors:
  • Classic Spring proxy-based AOP
  • @AspectJ annotation-driven aspects
  • Pure-POJO aspects
  • Injected AspectJ aspects (available in all versions of Spring)
The first three items are all variations on Spring’s proxy-based AOP. Consequently, Spring’s AOP support is limited to method interception. If your AOP needs exceed simple method interception (constructor or property interception, for example), you’ll want to consider implementing aspects in AspectJ, perhaps taking advantage of Spring DI to inject values into AspectJ-driven aspects.

14.  In Spring, aspects are woven into Spring-managed beans at runtime by wrapping them with a proxy class. The proxy class poses as the target bean, intercepting advised method calls and forwarding those calls to the target bean. Between the time when the proxy intercepts the method call and the time when it invokes the target bean’s method, the proxy performs the aspect logic.

15.  Spring doesn’t create a proxied object until that proxied bean is needed by the application. If you’re using an ApplicationContext, the proxied objects will be created when it loads all of the beans from the BeanFactory.

16.  Because it’s based on dynamic proxies, Spring only supports method join points. This is in contrast to some other AOP frameworks, such as AspectJ and JBoss, which provide field and constructor join points in addition to method pointcuts.

17.  In Spring AOP, pointcuts are defined using AspectJ’s pointcut expression language. For a more detailed discussion of AspectJ and AspectJ’s pointcut expression language, Please refer Ramnivas Laddad’s AspectJ in Action, Second Edition (Manning, 2009, www.manning.com/laddad2/).

18.  Spring only supports a subset of the pointcut designators available in AspectJ:
  • args(): Limits join-point matches to the execution of methods whose arguments are instances of the given types
  • @args(): Limits join-point matches to the execution of methods whose arguments’ runtime type are annotated with the given annotation types
  • execution(): Matches join points that are method executions, this is the primary pointcut designator you will use when working with Spring AOP
  • this(): Limits join-point matches to those where the bean reference of the AOP proxy is of a given type
  • target(): Limits join-point matches to those where the target object is of a given type
  • @target : Limits matching to join points where the class of the executing object has an annotation of the given type
  • within() : limits matching to join points within certain types (simply the execution of a method is invoked within a matching type when using Spring AOP)
  • @within() : limits matching to join points within types that have the given annotation (the execution of methods invoked in types with the given annotation when using Spring AOP)
  • @annotation - limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation

19.  Attempting to use any of AspectJ’s other designators will result in an IllegalArgumentException being thrown. execution designator is the only one that actually performs matches. The other designators are used to limit those matches. This means that execution is the primary designator you’ll use in every pointcut definition you write. You’ll use the other designators to constrain the pointcut’s reach.

20.  The pointcut expression shown below can be used to apply advice whenever an Instrument's play() method is executed:


You can confine the reach of that pointcut to only the com.springinaction.springidol package:


You’re free to use and in place of && when specifying pointcuts in a Spring XML-based configuration. Likewise, or and not can be used in place of || and ! .

21.  Spring 2.5 introduced a new bean() designator that lets you identify beans by their ID within a pointcut expression. bean() takes a bean ID or name as an argument and limits the pointcut’s effect to that specific bean:

execution(* com.springinaction.springidol.Instrument.play()) and bean(‘eddie’)

Here we’re saying that we want to apply aspect advice to the execution of an Instrument’s play() method, but limited to the bean whose ID is eddie.

22.  A key feature introduced in AspectJ 5 is the ability to use annotations to create aspects. Prior to AspectJ 5, writing AspectJ aspects involved learning a Java language extension. This new feature is commonly referred to as @AspectJ.

23.  The following shows the Audience class now annotated to be an aspect:
@Aspect

public class Audience {

  @Pointcut (“execution(* com.springinaction.springidol.Performer.perform(..))”)

  public void performance() {

  }

  @Before(“performance()”)

  public void takeSeats() {

    System.out.println(“The audience is taking their seats.”);

  }

  @Before(“performance()”)

  public void turnOffCellPhone() {

    System.out.println(“The audience is turning off their cellphones”);

  }

  @AfterReturning(“performance()”)

  public void applaud() {

    System.out.println(“CLAP CLAP CLAP CLAP”);

  }

  @AfterThrowing(“performance()”)

  public void demandRefund() {

    System.out.println(“Boo! We want our money back!”);
  } }
@Aspect annotation indicates that Audience isn’t just any POJO but is an aspect. The name of the pointcut is derived from the name of the method to which the @Pointcut annotation is applied. The actual body of the performance() method is irrelevant and in fact should be empty. You can also make the pointcut inline within the annotation:

@Before(“execution(* com.springinaction.springidol.Performer.perform(..))”)

24.  AspectJ provides five annotations for defining advice:

  • @After: The advice method is called after the advised method returns or throws an exception.
  • @AfterReturning: The advice method is called after the advised method returns.
  • @AfterThrowing: The advice method is called after the advised method throws an exception.
  • @Around: The advice method wraps the advised method.
  • @Before: The advice method is called before the advised method is called.

25.  You must declare an autoproxy bean in the Spring context that knows how to turn @AspectJ-annotated beans into proxy advice. <aop:aspectj-autoproxy/> will create an AnnotationAwareAspectJAutoProxyCreator bean in the Spring context and will automatically proxy beans whose methods match the pointcuts. If you’re using JavaConfig, you can turn on auto-proxying by applying the @EnableAspectJAutoProxy annotation at the class level of the configuration class.

26.  It’s tricky to share information between before advice and after advice without resorting to storing that information in member variables. Around advice has an advantage over before and after advice in this regard. With around advice, you can accomplish the same thing you could with distinct before and after advice, but you can do it in a single method.

27.  Methods annotated with @Around are to be around advice. They must take a ProceedingJoinPoint object as an argument and then call the proceed() method on that object :


What’s also interesting is that just as you can omit a call to the proceed() method to block access to the advised method, you can also invoke it multiple times from within the advice. One reason for doing this may be to implement retry logic to perform repeated attempts on the advised method should it fail.

28.  You can supply parameters to advice using @AspectJ:
@Aspect
public class TrackCounter {

    private Map<Integer, Integer> trackCounts = new HashMap<Integer, Integer>();

    @Pointcut(“execution(* soundsystem.CompactDisc.playTrack(int)) && args(trackNumber)”)

public void trackPlayed(int trackNumber) {

}

    @Before(“trackPlayed(trackNumber)”)

    public void countTrack(int trackNumber) {

        int currentCount = trackCounts.contains(trackNumber) ? trackCounts.get(trackNumber) : 0;

        trackCounts.put(trackNumber, currentCount + 1);

    }

}

the pointcut also declares parameters to be supplied to the advice method:

The args(trackNumber) qualifier indicates that any int argument that is passed into the execution of playTrack() should also be passed into the advice. The parameter name, trackNumber, also matches the parameter in the pointcut method signature.

29.  Using an AOP concept known as introduction, aspects can attach all new methods to Spring beans. In Spring, aspects are just proxies that implement the same interface(s) as the beans that they wrap. What if, in addition to implementing those interfaces, the proxy were to also be exposed through some new interface? Then any bean that’s advised by the aspect will appear to implement the new interface, even if its underlying implementation class doesn’t:


30.  To introduces the Encoreable interface to all the existing Performance implementations:

@Aspect

public class EncoreableIntroducer {

  @DeclareParents(value="concert.Performance+", defaultImpl=DefaultEncoreable.class)

  public static Encoreable encoreable;

}

   The @DeclareParents annotation is made up of three parts:

  • The value attribute identifies the kinds of beans that should be introduced with the interface. (The plus sign at the end specifies any subtype of Performance, as opposed to Performance itself.)
  • The defaultImpl attribute identifies the class that will provide the implementation for the introduction.
  • The static property that is annotated by @DeclareParents specifies the interface that’s to be introduced.


31.  To use Spring AOP configuration elements you need aop namespace :

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


32.  The Spring AOP configuration elements are :

  • <aop:advisor> : Defines an AOP advisor.
  • <aop:after> : Defines an AOP after advice (regardless of whether the advised method returns successfully).
  • <aop:after-returning> : Defines an AOP after-returning advice.
  • <aop:after-throwing> : Defines an AOP after-throwing advice.
  • <aop:around> : Defines an AOP around advice.
  • <aop:aspect> : Defines an aspect.
  • <aop:aspectj-autoproxy> : Enables annotation-driven aspects using @AspectJ.
  • <aop:before> : Defines an AOP before advice.
  • <aop:config> : The top-level AOP element. Most <aop:*> elements must be contained within <aop:config>.
  • <aop:declare-parents> : Introduces additional interfaces to advised objects that are transparently implemented.
  • <aop:pointcut> : Defines a pointcut.

33.  <aop:aspect> has one distinct advantage over @AspectJ in that you don’t need the source code of the class that’s to provide the aspect’s functionality. With @AspectJ, you must annotate the class and methods, which requires having the source code. But <aop:aspect> can reference any bean.

34.  Using Spring’s AOP configuration elements below, you can turn the audience bean into an aspect:
<aop:config>

    <aop:aspect ref=”audience”>

        <aop:before pointcut=”execution(* com.springinaction.springidol.Performer.perform(..))” method=”takeSeats” />

        <aop:before pointcut=”execution(* com.springinaction.springidol.Performer.perform(..))” method=”turnOffCellPhone” />

        <aop:after-returning pointcut=”execution(* com.springinaction.springidol.Performer.perform(..))” method=”applaud” />

        <aop:after-throwing pointcut=”execution(* com.springinaction.springidol.Performer.perform(..))” method=”demandRefund” />

    </aop:aspect>

</aop:config>

The following figure shows how the advice logic is woven into the business logic:

35.  The following XML shows how the <aop:pointcut> element is used within the <aop:aspect> element to define a named pointcut that can be used by all of the advice elements:

<aop:config>

    <aop:aspect ref=”audience”>

        <aop:pointcut id=”performance” expression=”execution(* com.springinaction.springidol.Performer.perform(..))” />

        <aop:before pointcut-ref=”performance” method=”takeSeats” />

        <aop:before pointcut-ref=”performance” method=”turnOffCellPhone” />

        <aop:after-returning pointcut-ref=”performance” method=”applaud” />

        <aop:after-throwing pointcut-ref=”performance” method=”demandRefund” />

    </aop:aspect>

</aop:config>

You can also define pointcuts that can be used across multiple aspects by placing the <aop:pointcut> elements within the scope of the <aop:config> element.

36.  The following configuration will pass the advised method’s parameters to the advice:


Here, args is used in a binding form. If a parameter name is used in place of a type name in an args expression, then the value of the corresponding argument will be passed as the parameter value when the advice is invoked. Or you can use arg-names attribute to specify the arguments you want to pass the value to.

37.  The following configurations make the beans whose type matches the Performer interface (per the types-matching attribute) should have implement Contestant interface (per the implement-interface attribute).
<aop:aspect>

  <aop:declare-parents

    types-matching="com.springinaction.springidol.Performer+"

    implement-interface="com.springinaction.springidol.Contestant"

    default-impl="com.springinaction.springidol.GraciousContestant"

    />
</aop:aspect>

In this case, we’re using the default-impl attribute to explicitly identify the implementation by its fully-qualified class name. Alternatively, we could’ve identified it using the delegate-ref attribute  refers to a Spring bean as the introduction delegate. @DeclareParents is an @AspectJ annotation. @AspectJ is a project that’s separate from Spring and thus its annotations aren’t bean-aware.

38.  AspectJ aspects can be woven into your application without involving Spring at all. But if you want to use Spring’s dependency injection to inject collaborators into an AspectJ aspect, you’ll need to declare the aspect as a <bean> in Spring’s configuration. Normally, Spring beans are instantiated by the Spring container, but AspectJ aspects are created by the AspectJ runtime. You need a way for Spring to get a handle to the AspectJ aspect instance that has already been created by AspectJ so that you can inject it with collaborators. Conveniently, all AspectJ aspects provide a static aspectOf() method that returns the singleton instance of the aspect. So to get an instance of the aspect, you must use factory-method to invoke the aspectOf() method instead of trying to call the aspect’s constructor.

2015年9月10日星期四

3. Spring in Action -- Advanced wiring

1.  An environment-specific decision is made as to which beans will and won’t be created. But rather than make that decision at build time, Spring waits to make the decision at runtime. Consequently, the same deployment unit (perhaps a WAR file) will work in all environments without being rebuilt. In version 3.1, Spring introduced bean profiles. To use profiles, you must gather all the varying bean definitions into one or more profiles and then make sure the proper profile is active when your application is deployed in each environment.

2.  In Java configuration, you can use the @Profile annotation to specify which profile a bean belongs to:

@Configuration

@Profile("dev")

public class DevelopmentProfileConfig {

  @Bean(destroyMethod="shutdown")

  public DataSource dataSource() {
      …
  }
}

The @Profile annotation applied at the class level tells Spring that the beans in this configuration class should be created only if the dev profile is active.

3.  In Spring 3.1, you could only use the @Profile annotation at the class level. Starting with Spring 3.2, however, you can use @Profile at the method level, alongside the @Bean annotation.

4.  Any bean that isn’t given a profile will always be created, regardless of what profile is active.

5.  You can also configure profiled beans in XML by setting the profile attribute of the <beans> element. Rather than creating a proliferation of XML files for each environment, you also have the option of defining <beans> elements embedded in the root <beans> element.

6.  If spring.profiles.active is set, then its value determines which profiles are active. But if spring.profiles.active isn’t set, then Spring looks to spring.profiles.default. If neither spring.profiles.active nor spring.profiles.default is set, then there are no active profiles, and only those beans that aren’t defined as being in a profile are created. You can activate multiple profiles at the same time by listing the profile names, separated by commas.

7.  There are several ways to set these properties:
  • As initialization parameters on DispatcherServlet
  • As context parameters of a web application
  • As JNDI entries
  • As environment variables
  • As JVM system properties
  • Using the @ActiveProfiles annotation on an integration test class

8.  Spring 4 offers a more general-purpose mechanism for conditional bean definitions where the condition is up to you. Spring 4 introduced a new @Conditional annotation that can be applied to @Bean methods. If the prescribed condition evaluates to true, then the bean is created. Otherwise the bean is ignored. @Conditional is given a Class that specifies the condition. The class given to @Conditional can be any type that implements the Condition interface:

   public interface Condition {

    boolean matches(ConditionContext ctx, AnnotatedTypeMetadata metadata);

}

ConditionContext is an interface that looks something like this

public interface ConditionContext {

  BeanDefinitionRegistry getRegistry();

  ConfigurableListableBeanFactory getBeanFactory();

  Environment getEnvironment();

  ResourceLoader getResourceLoader();

  ClassLoader getClassLoader();

}

From the ConditionContext, you can do the following:
  • Check for bean definitions via the BeanDefinitionRegistry returned from getRegistry().
  • Check for the presence of beans, and even dig into bean properties via the ConfigurableListableBeanFactory returned from getBeanFactory().
  • Check for the presence and values of environment variables via the Environment retrieved from getEnvironment().
  • Read and inspect the contents of resources loaded via the ResourceLoader returned from getResourceLoader().
  • Load and check for the presence of classes via the ClassLoader returned from getClassLoader().
AnnotatedTypeMetadata offers you a chance to inspect annotations that may also be placed on the @Bean method:

public interface AnnotatedTypeMetadata {

  boolean isAnnotated(String annotationType);

  Map<String, Object> getAnnotationAttributes(String annotationType);

  Map<String, Object> getAnnotationAttributes(

          String annotationType, boolean classValuesAsString);

  MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType);

  MultiValueMap<String, Object> getAllAnnotationAttributes(

          String annotationType, boolean classValuesAsString);

}

9.  Starting with Spring 4, the @Profile annotation has been refactored to be based on @Conditional and the Condition interface:

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE, ElementType.METHOD})

@Documented

@Conditional(ProfileCondition.class)

public @interface Profile {

  String[] value();

}

ProfileCondition implements Condition and considers several factors from both ConditionContext and AnnotatedTypeMetadata in making its decision:

class ProfileCondition implements Condition {

  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

    if (context.getEnvironment() != null) {

      MultiValueMap<String, Object> attrs =

          metadata.getAllAnnotationAttributes(Profile.class.getName());

      if (attrs != null) {

        for (Object value : attrs.get("value")) {

          if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
            return true;
          }

        }

        return false;

      }

    }

    return true;

  }

}

10.  When there’s more than one matching bean, the ambiguity prevents Spring from autowiring the property, constructor argument, or method parameter and Spring throws a NoUniqueBeanDefinitionException.

11.  You can avoid autowiring ambiguity by designating one of the candidate beans as a primary bean. In the event of any ambiguity, Spring will choose the primary bean over any other candidate beans. You can express that favorite choice in Spring using the @Primary annotation. @Primary can be used either alongside @Component for beans that are component-scanned or alongside @Bean for beans declared in Java configuration. If you’re configuring your beans in XML, The <bean> element has a primary attribute to specify a primary bean.

12.  The primary attribute defaults to true. That means that all autowire candidates will be primary (and thus none will be preferred). So, to use primary, you’ll need to set it to false for all of the beans that are not the primary choice. If you’d rather eliminate some beans from consideration when autowiring, then you can set their autowire-candidate attribute to false.

13.  The @Qualifier annotation is the main way to work with qualifiers. It can be applied alongside @Autowired or @Inject at the point of injection to specify which bean you want to be injected. The parameter given to @Qualifier is the ID of the bean that you want to inject. To be more precise, @Qualifier ("iceCream") refers to the bean that has the String “iceCream” as a qualifier. For lack of having specified any other qualifiers, all beans are given a default qualifier that’s the same as their bean ID.

14.  Instead of relying on the bean ID as the qualifier, you can assign your own qualifier to a bean. All you need to do is place the @Qualifier annotation on the bean declaration. It can be applied alongside @Component and the @Bean annotation.

15.  Java doesn’t allow multiple annotations of the same type to be repeated on the same item. Java 8 allows repeated annotations, as long as the annotation is annotated with @Repeatable. Even so, Spring’s @Qualifier annotation isn’t annotated with @Repeatable.

16.  You can create a custom qualifier annotation by annotating the annotation class with @Qualifier:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold { }

At the injection point, you can use any combination of custom qualifier annotations necessary to narrow the selection to the one bean that meets all your specifications.

17. You can also attach a qualifier to a bean in XML configuration through qualifier element :

<bean class="com.springinaction.springidol.Guitar">

  <qualifier value="stringed" />

</bean>

18.  Known in the Java Community Process as JSR-330 or more commonly as at inject, this specification brings a common dependency injection model to Java. As of Spring 3, Spring supports the at inject model. Google Guice and Picocontainer also support the JSR-330 model.

19.  The centerpiece of JSR-330 is the @Inject annotation. This annotation is an almost complete drop-in replacement for Spring’s @Autowired annotation.

20.  Just like @Autowired, @Inject can be used to autowire properties, methods, and constructors. Unlike @Autowired, @Inject doesn’t have a required attribute. Therefore, @Inject-annotated dependencies are expected to be fulfilled, failing with an exception if they’re not.

21.  @Inject’s answer to the @Qualifier annotation is the @Named annotation. The key difference between Spring’s @Qualifier and JSR-330’s @Named is one of semantics. Whereas @Qualifier helps narrow the selection of matching beans (using the bean’s ID by default), @Named specifically identifies a selected bean by its ID.

22.  Rather than inject a reference directly, you could ask @Inject to inject a Provider. The Provider interface enables, among other things, lazy injection of bean references and injection of multiple instances of a bean:

private Set<Knife> knives;

@Inject

public KnifeJuggler(Provider<Knife> knifeProvider) {

    knives = new HashSet<Knife>();

    for (int i = 0; i < 5; i++) {

        knives.add(knifeProvider.get());

   }

}

At this point, only the provider is injected. No actual Knife object will be injected until the get() method is called on the provider. Suppose the Knife bean is a prototype, we know that the Set of knives will be given five distinct Knife objects to work it.

23.  JSR-330 has its own @Qualifier annotation in the javax.inject package. Unlike Spring’s @Qualifier, the JSR-330 version isn’t intended to be used on its own. Instead, you’re expected to use it to create custom qualifier annotations, much as we did with Spring’s @Qualifier. In fact, the @Named annotation is just an annotation that’s itself annotated with @Qualifier.

24.  Spring 3.0 introduced @Value, a new wiring annotation that lets you wire primitive values such as int, boolean, and String using annotations. To use it, annotate a property, method, or method parameter with @Value and pass in a String expression to be wired into the property. The String parameter passed into @Value is just an expression—it can evaluate down to any type and thus @Value can be applied to just about any kind of property. SpEL lets you dynamically evaluate complex expressions, at runtime, into values to be wired into bean properties. That makes @Value a powerful wiring option:

@Value("#{systemProperties.myFavoriteSong}")

private String song;

25.  Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.

26.  The <context:component-scan> element does everything that <context:annotation-config> does, plus it configures Spring to automatically discover beans and declare them for you. By default, <context:component-scan> looks for classes that are annotated with one of a handful of special stereotype annotations:
  • @Component—A general-purpose stereotype annotation indicating that the class is a Spring component
  • @Controller—Indicates that the class defines a Spring MVC controller
  • @Repository—Indicates that the class defines a data repository
  • @Service—Indicates that the class defines a service
  • Any custom annotation that is itself annotated with @Component
By default, the bean’s ID will be generated by camel-casing the class name. You can also specify a bean ID as a parameter to @Component.

27.  By adding <context:include-filter> and/or <context:exclude-filter> subelements to <context:component-scan>, you can tweak component-scanning behavior to your heart’s content:

<context:component-scan

        base-package="com.springinaction.springidol">

      <context:include-filter type="assignable"

          expression="com.springinaction.springidol.Instrument"/>

</context:component-scan>

In this case, we’re asking for all classes that are assignable to Instrument to be automatically registered as Spring beans.

28.  Component scanning can be customized using any of five kinds of filter types:
  • annotation (default): Filters scan classes looking for those annotated with a given annotation at the type level. The annotation to scan for is specified in the expression attribute.
  • assignable : Filters scan classes looking for those that are assignable to the type specified in the expression attribute.
  • aspectj : Filters scan classes looking for those that match the AspectJ type expression specified in the expression attribute.
  • custom : Uses a custom implementation of org.springframework.core.type.TypeFilter, as specified in the expression attribute.
  • regex : Filters scan classes looking for those whose class names match the regular expression specified in the expression attribute.

29.  By default, all Spring beans are singletons. When the container dispenses a bean (either through wiring or as the result of a call to the container’s getBean() method) it’ll always hand out the exact same instance of the bean. You have the option of declaring a scope for a bean. To force Spring to produce a new bean instance each time one is needed, you should declare the bean’s scope attribute to be prototype.

30.  Spring’s bean scopes let you declare the scope under which beans are created without hard-coding the scoping rules in the bean class itself:

Scope
What it does
singleton
Scopes the bean definition to a single instance per Spring container (default).
prototype
Allows a bean to be instantiated any number of times (once per use).
request
Scopes a bean definition to an HTTP request. Only valid when used with a web-capable Spring context (such as with Spring MVC).
session
Scopes a bean definition to an HTTP session. Only valid when used with a web-capable Spring context (such as with Spring MVC).
global-session
Scopes a bean definition to a global HTTP session. Only valid when used in a portlet context.


31.  Spring’s notion of singletons is limited to the scope of the Spring context. Unlike true singletons, which guarantee only a single instance of a class per classloader, Spring’s singleton beans only guarantee a single instance of the bean definition per the application context.

32.  To select an alternative type, you can use the @Scope annotation, either in conjunction with the @Component annotation or with the @Bean annotation. You can specify prototype scope by using the ConfigurableBeanFactory.SCOPE_PROTOTYPE. You could also use @Scope("prototype"), but using the SCOPE_PROTOTYPE constant is safer and less prone to mistakes. In the event that you’re configuring the bean in XML, you can set the scope using the scope attribute of the <bean> element.

33.  To apply session scope:

@Component

@Scope(

    value=WebApplicationContext.SCOPE_SESSION,

    proxyMode=ScopedProxyMode.INTERFACES)

public ShoppingCart cart() { ... }


The proxyMode attribute addresses a problem encountered when injecting a session- or request-scoped bean into a singleton-scoped bean:

@Component

public class StoreService {

  @Autowired

  public void setShoppingCart(ShoppingCart shoppingCart) {

    this.shoppingCart = shoppingCart;

  }

  ...

}

Because StoreService is a singleton bean, it will be created as the Spring application context is loaded. As it’s created, Spring will attempt to inject ShoppingCart into the setShoppingCart() method. But the ShoppingCart bean, being session scoped, doesn’t exist yet. There won’t be an instance of ShoppingCart until a user comes along and a session is created. Moreover, You don’t want Spring to inject just any single instance of ShoppingCart into StoreService. You want StoreService to work with the ShoppingCart instance for whichever session happens to be in play when StoreService needs to work with the shopping cart. Instead of injecting the actual ShoppingCart bean into StoreService, Spring should inject a proxy of the ShoppingCart bean. This proxy will expose the same methods as ShoppingCart so that for all StoreService knows, it is the shopping cart. But when StoreService calls methods on ShoppingCart, the proxy will lazily resolve it and delegate the call to the actual session-scoped ShoppingCart bean:


proxyMode is set to ScopedProxyMode.INTERFACES, indicating that the proxy should implement the ShoppingCart interface and delegate to the implementation bean. This is fine (and the most ideal proxy mode) as long as ShoppingCart is an interface and not a class. But if ShoppingCart is a concrete class, there’s no way Spring can create an interface-based proxy. Instead, it must use CGLib to generate a class-based proxy. So, if the bean type is a concrete class, you must set proxyMode to ScopedProxyMode.TARGET_CLASS to indicate that the proxy should be generated as an extension of the target class.

34.  <aop:scoped-proxy> is the Spring XML configuration’s counterpart to the @Scope annotation’s proxyMode attribute. It tells Spring to create a scoped proxy for the bean. By default, it uses CGLib to create a target class proxy. But you can ask it to generate an interface-based proxy by setting the proxy-target-class attribute to false:

<bean id="cart"

      class="com.myapp.ShoppingCart"

      scope="session">

  <aop:scoped-proxy proxy-target-class="false" />

</bean>

35. Spring offers two ways of evaluating values at runtime:

  • Property placeholders
  • The Spring Expression Language (SpEL)


36.  The following codes show a basic Spring configuration class that uses external properties to wire up a BlankDisc bean:

@Configuration

@PropertySource(“classpath:/com/soundsystem/app.properties”)

public class ExpressiveConfig{

    @Autowired

    Environment env;

    @Bean

    public BlankDisc disc() {

    return new BlankDisc( env.getProperty(“disc.title”) , env.getProperty(“disc.artist”));

  }

}

@PropertySource references a file named app.properties in the classpath. This properties file is loaded into Spring’s Environment, from which it can be retrieved later.

37.  If you use getProperty() methods of Environment class without specifying a default value, you’ll receive null if the property isn’t defined. If you want to require that the property be defined, you can use getRequiredProperty() in which case, if the property is undefined, an IllegalStateException will be thrown.

38.  Environment also offers some methods for checking which profiles are active:

  • String[] getActiveProfiles() —Returns an array of active profile names
  • String[] getDefaultProfiles() —Returns an array of default profile names
  • boolean acceptsProfiles(String... profiles) —Returns true if the environment supports the given profile(s)

39.  In Spring wiring, placeholder values are property names wrapped with ${ ... }:

<bean id="sgtPeppers"

      class="soundsystem.BlankDisc"

      c:_title="${disc.title}"

      c:_artist="${disc.artist}" />

40.  When relying on component-scanning and autowiring to create and initialize your application components, you can use the @Value annotation in much the same way as you might use the @Autowired annotation:

public BlankDisc(

      @Value("${disc.title}") String title,

      @Value("${disc.artist}") String artist) {

  this.title = title;

  this.artist = artist;

}


41.  In order to use placeholder values, you must configure either a PropertyPlaceholderConfigurer bean or a PropertySourcesPlaceholderConfigurer bean. Starting with Spring 3.1, PropertySourcesPlaceholderConfigurer is preferred because it resolves placeholders against the Spring Environment and its set of property sources. If you’d rather use XML configuration, the <context:property-placeholder> element from Spring’s context namespace will give you a PropertySourcesPlaceholderConfigurer bean.

42.  Spring 3 introduced the Spring Expression Language (SpEL), a powerful yet succinct way of wiring values into a bean’s properties or constructor arguments using expressions that are evaluated at runtime. SpEL has a lot of tricks up its sleeves, including

  • The ability to reference beans by their ID
  • Invoking methods and accessing properties on objects
  • Mathematical, relational, and logical operations on values
  • Regular expression matching
  • Collection manipulation


43.  SpEL expressions are framed with #{ ... }, much as property placeholders are framed with ${ ... }. What follows could be mixed with non-SpEL values as well:

<property name="message" value="The value is #{5}"/>

44.  Numbers can even be expressed in scientific notation:

<property name="capacity" value="#{1e4}"/>

45.  Literal String values can be expressed in SpEL with either single or double quote marks:

<property name="name" value="#{'Chuck'}"/>

46.  A couple of other literal values you may use are the Boolean true and false values:

<property name="enabled" value="#{false}"/>

47.  You could use SpEL to wire one bean into another bean’s property by using the bean ID as the SpEL expression:

<property name="instrument" value="#{saxophone}"/>

48.  You can refer to another bean’s property using the Spring Expression Language:

<bean id="carl" class="com.springinaction.springidol.Instrumentalist">
    <property name="song" value="#{kenny.song}" />
</bean>

The first part (the part before the period delimiter) refers to the kenny bean by its ID. The second part refers to the song attribute of the kenny bean. It’s effectively as if you programmatically performed the following Java code:

Instrumentalist carl = new Instrumentalist();
carl.setSong(kenny.getSong());

49.  You could also invoke a method of a bean:

<property name="song" value="#{songSelector.selectSong()}"/>

50.  ?. operator makes sure that the item to its left isn’t null before accessing the thing to its right:

<property name="song" value="#{songSelector.selectSong()?.toUpperCase()}"/>

If selectSong() were to return a null, then SpEL wouldn’t even try to invoke toUpperCase() on it.

51.  The key to working with class-scoped methods and constants in SpEL is to use the T() operator. The result of the T(java.lang.Math) is a Class object that represents java.lang.Math.

52.  You can reference the Math class’s PI constant by:

<property name="multiplier" value="#{T(java.lang.Math).PI}"/>

Similarly, static methods can also be invoked on the result of the T() operator:

<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>

53.  SpEL includes several operators that you can use to manipulate the values of an expression:

Operation type
Operators
Arithmetic
+, -, *, /, %, ^
Relational
<, >, ==, <=, >=, It, gt, eq, le, ge
Logical
and, or, not, !
Conditional
?: (ternary), ?: (Elvis)
Regular expression
matches

54.  Unlike Java, SpEL also offers a power-of operator in the form of the carat:

<property name="area" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>

55.  It is consistent with Java in that the + operator can be used to concatenate String values.

56.  The less-than and greater-than symbols pose a problem when using these expressions in Spring’s XML configuration, as they have special meaning in XML. So, when using SpEL in XML, it’s best to use SpEL’s textual alternatives to these operators:

Operation
Symbolic
Textual
Equals
==
eq
Less than
lt
Less than or equals
<=
le
Greater than
gt
Greater than or equals
>=
ge

57.  SpEL’s ternary operator works the same as Java’s ternary operator:

<property name="instrument" 
    value="#{songSelector.selectSong()=='Jingle Bells'?piano:saxophone}"/>

58.  SpEL offers a variant of the ternary operator that simplifies the following expression:

<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}"/>

which is Elvis operator:

<property name="song" value="#{kenny.song ?: 'Greensleeves'}"/>

59.  The matches operator attempts to apply a regular expression (given as its right-side argument) against a String value (given as the left-side argument). The result of a matches evaluation is a Boolean value: true if the value matches the regular expression, false otherwise:

<property name="validEmail" 
    value="#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'}"/>

60.  The <util:list> element comes from Spring’s util namespace. It effectively creates a bean of type java.util.List that contains all of the values or beans that it contains:

<util:list id="cities">
  <bean class="com.habuma.spel.cities.City"
     p:name="Chicago" p:state="IL" p:population="2853114"/>
  <bean class="com.habuma.spel.cities.City"
     p:name="Atlanta" p:state="GA" p:population="537958"/>
  ...
</util:list>

61.  The most basic thing we could do with a collection is extract a single element out of the list and wire it into a property:

<property name="chosenCity" 
    value="#{cities[T(java.lang.Math).random() * cities.size()]}"/>

62.  The [] operator is also good for retrieving a member of a java.util.Map collection:

<property name="chosenCity" value="#{cities['Dallas']}"/>

63.  To load a properties configuration file into Spring:

<util:properties id="settings" location="classpath:settings.properties"/>

Here the settings bean will be a java.util.Properties that contains all of the entries in the file named settings.properties. With SpEL, you can access a property from <util:properties> in the same way you access a member of a Map:

<property name="accessToken" value="#{settings['twitter.accessToken']}"/>

64.  Spring makes two special selections of properties available to SpEL: systemEnvironment and systemPropertiessystemEnvironment contains all of the environment variables on the machine running the application:

<property name="homePath" value="#{systemEnvironment['HOME']}"/>

Meanwhile, systemProperties contains all of the properties that were set in Java as the application started (typically using the -D argument):

<property name="homePath" value="#{systemProperties['application.home']}"/>

65.  The [] operator can also be used on String values to retrieve a single character by its index within the String.

66.  The selection operator .?[] will create a new collection whose members include only those members from the original collection that meet the criteria expressed between the square braces:

<property name="bigCities" value="#{cities.?[population gt 100000]}"/>

SpEL also offers two other selection operators, .^[] and .$[], for selecting the first and last matching items (respectively) from a collection.

67.  Collection projection involves collecting a particular property from each of the members of a collection into a new collection. SpEL’s projection operator (.![]) can do exactly that:

<property name="cityNames" value="#{cities.![name]}"/>

But projection isn’t limited to projecting a single property:

<property name="cityNames" value="#{cities.![name + ', ' + state]}"/>

Now the cityNames property will be given a list containing values such as “Chicago, IL”, “Atlanta, GA”, and “Dallas, TX”.

2015年8月14日星期五

JNDI Basics


Overview

    Finding resources is of particular importance in large-scale enterprise environments, where the applications you build may depend on services provided by applications written by other groups in other departments. A well-designed naming infrastructure makes such projects possible -- and the lack of one makes them impossible. In fact, many business-process reengineering efforts begin with the design and implementation of a robust, enterprise-wide naming and directory infrastructure.

   The Java Naming and Directory Interface™ (JNDI) is an application programming interface (API) that provides naming and directory functionality to applications written using the Java™ programming language. It provides a common-denominator interface to many existing naming services. As such, JNDI was not designed to replace existing technology; instead, it provides a common interface to existing naming services.

  The primary function of a naming system is to bind names to objects (or, in some cases, to references to objects -- more on which in a moment). In order to be a naming service, a service must at the very least provide the ability to bind names to objects and to look up objects by name. JNDI provides an interface that supports all this common functionality.

Architecture
 
The JNDI architecture consists of an API and a service provider interface (SPI). Java applications use the JNDI API to access a variety of naming and directory services. The SPI enables a variety of naming and directory services to be plugged in transparently, thereby allowing the Java application using the JNDI API to access their services.


    JNDI is included in the Java SE Platform. To use the JNDI, you must have the JNDI classes and one or more service providers. The JDK includes service providers for the following naming/directory services:

  • Lightweight Directory Access Protocol (LDAP) : Developed by the University of Michigan; as its name implies, it is a lightweight version of DAP (Directory Access Protocol), which in turn is part of X.500, a standard for network directory services. 
  • Common Object Request Broker Architecture (CORBA) Common Object Services (COS) name service : The naming service for CORBA applications; allows applications to store and access references to CORBA objects.
  • Java Remote Method Invocation (RMI) Registry : A bootstrap naming service that is used by RMI servers on the same host to bind remote objects to names. Clients on local and remote hosts can then look up remote objects and make remote method invocations.
  • Domain Name Service (DNS) : The Internet's naming service; maps people-friendly names into computer-friendly IP addresses. DNS is a distributed naming service, meaning that the service and its underlying database is spread across many hosts on the Internet.
  • Network Information System ( NIS and NIS+ ) : Network naming services developed by Oracle. Both allow users to access files and applications on any host with a single ID and password.

Other service providers can be downloaded from the JNDI page or obtained from other vendors.


An introduction to naming services

    Naming Concepts

    A naming service's primary function is to map people friendly names to objects, such as addresses, identifiers, or objects typically used by computer programs. Clients use the naming service to locate objects by name.



For example, the Internet Domain Name System (DNS) maps machine names to IP Addresses:

www.example.com ==> 192.0.2.5

A file system maps a filename to a file reference that a program can use to access the contents of the file.

c:\bin\autoexec.bat ==> File Reference

    Names

To look up an object in a naming system, you supply it the name of the object. The naming system determines the syntax that the name must follow. This syntax is sometimes called the naming systems naming convention. All objects in a naming system are named in the same way (that is, they subscribe to the same naming convention). A name is made up components. A name's representation consist of a component separator marking the components of the name.

The most noticeable difference among each service is the way each naming service requires names to be specified -- its naming convention:

Naming SystemComponent SeparatorNames
UNIX file system"/"/usr/hello
DNS"."seanzhou1023.blogspot.com
LDAP"," and "="cn=Sean, o=Paypal, c=US


The UNIX file system's naming convention is that a file is named from its path relative to the root of the file system, with each component in the path separated from left to right using the forward slash character ("/"). The UNIX pathname, /usr/hello, for example, names a file hello in the file directory usr, which is located in the root of the file system.

DNS naming convention calls for components in the DNS name to be ordered from right to left and delimited by the dot character ("."). The name "seanzhou1023.blogspot.com" names a machine called "seanzhou1023" in the "blogspot.com" domain. Likewise, the name "blogspot.com" names the domain "blogspot" in the top-level domain "com."

The Lightweight Directory Access Protocol (LDAP) naming convention orders components from right to left, delimited by the comma character (","). Components in an LDAP name must be specified as name/value pairs with the name and value separated by an equals character ("="). The name "cn=Sean, o=Paypal, c=US" names the person "cn=Sean" in the organization "o=Paypal, c=US." Likewise, the name "o=Paypal, c=US" names the organization "o=Paypal" in the country "c=US."

JNDI solves this problem with the Name class and its subclasses and helper classes. The Name class represents a name composed of an ordered sequences of subnames, and provides methods for working with names independent of the underlying naming service.

    Bindings

The association of a name with an object is called a binding. A naming service maintains a set of bindings. A file name is bound to a file. The DNS contains bindings that map machine names to IP addresses. An LDAP name is bound to an LDAP entry.

    References and Addresses

Depending on the naming service, some objects cannot be stored directly by the naming service; that is, a copy of the object cannot be placed inside the naming service. Instead, they must be stored by reference; that is, a pointer or reference to the object is placed inside the naming service. A reference represents information about how to access an object. Typically, it is a compact representation that can be used to communicate with the object, while the object itself might contain more state information. Using the reference, you can contact the object and obtain more information about the object.

For example, an airplane object might contain a list of the airplane's passengers and crew, its flight plan, and fuel and instrument status, and its flight number and departure time. By contrast, an airplane object reference might contain only its flight number and departure time. The reference is a much more compact representation of information about the airplane object and can be used to obtain additional information. A file object, for example, is accessed using a file reference. A printer object, for example, might contain the state of the printer, such as its current queue and the amount of paper in the paper tray. A printer object reference, on the other hand, might contain only information on how to reach the printer, such as its print server name and printing protocol.

Although in general a reference can contain any arbitrary information, it is useful to refer to its contents as addresses (or communication end points): specific information about how to access the object.

    Context

A context is a set of name-to-object bindings. Every context has an associated naming convention. A context always provides a lookup (resolution) operation that returns the object, it typically also provides operations such as those for binding names, unbinding names, and listing bound names. A name in one context object can be bound to another context object (called a subcontext) that has the same naming convention.



A file directory, such as /usr, in the UNIX file system represents a context. A file directory named relative to another file directory represents a subcontext (UNIX users refer to this as a subdirectory). That is, in a file directory /usr/bin, the directory bin is a subcontext of usr. A DNS domain, such as COM, represents a context. A DNS domain named relative to another DNS domain represents a subcontext. For the DNS domain Sun.COM, the DNS domain Sun is a subcontext of COM.

Finally, an LDAP entry, such as c=us, represents a context. An LDAP entry named relative to another LDAP entry represents a subcontext. For the LDAP entry o=sun,c=us, the entry o=sun is a subcontext of c=us.

Naming Systems and Namespaces

A naming system is a connected set of contexts of the same type (they have the same naming convention) and provides a common set of operations.

A system that implements the DNS is a naming system. A system that communicates using the LDAP is a naming system.

A naming system provides a naming service to its customers for performing naming-related operations. A naming service is accessed through its own interface. The DNS offers a naming service that maps machine names to IP addresses. LDAP offers a naming service that maps LDAP names to LDAP entries. A file system offers a naming service that maps filenames to files and directories.

A namespace is the set of all possible names in a naming system. The UNIX file system has a namespace consisting of all of the names of files and directories in that file system. The DNS namespace contains names of DNS domains and entries. The LDAP namespace contains names of LDAP entries.

An introduction to directory services

    Directory Concepts

A directory service is an extension to a naming service. It associates names with objects and also associates such objects with attributes:
directory service = naming service + objects containing attributes
You not only can look up an object by its name but also get the object's attributes or search for the object based on its attributes.




In fact, most existing products provide both sets of functionality. Naming services provide name-to-object mapping, and directory services provide information about the objects and tools for searching for them.

An example is the telephone company's directory service. It maps a subscriber's name to his address and phone number.

A directory object represents an object in a computing environment. A directory object can be used, for example, to represent a printer, a person, a computer, or a network. A directory object contains attributes that describe the object that it represents.

Attributes

A directory object can have attributes. For example, a printer might be represented by a directory object that has as attributes its speed, resolution, and color. A user might be represented by a directory object that has as attributes the user's e-mail address, various telephone numbers, postal mail address, and computer account information.

An attribute has an attribute identifier and a set of attribute values. An attribute identifier is a token that identifies an attribute independent of its values. For example, two different computer accounts might have a "mail" attribute; "mail" is the attribute identifier. An attribute value is the contents of the attribute. The email address, for example, might have:

Attribute Identifier : mail
Attribute Value : seanzhou1023@gmail.com

Directories and Directory Services

A directory is a connected set of directory objects. A directory service is a service that provides operations for creating, adding, removing, and modifying the attributes associated with objects in a directory. The service is accessed through its own interface.

Network Information Service (NIS) is a directory service available on the UNIX operating system for storing system-related information, such as that relating to machines, networks, printers, and users.

Oracle Directory Server is a general-purpose directory service based on the Internet standard LDAP.

Directories often arrange their objects in a hierarchy. For example, the LDAP arranges all directory objects in a tree, called a directory information tree (DIT). Within the DIT, an organization object, for example, might contain group objects that might in turn contain person objects. When directory objects are arranged in this way, they play the role of naming contexts in addition to that of containers of attributes.

Search Service

You can look up a directory object by supplying its name to the directory service. Alternatively, many directories, such as those based on the LDAP, support the notion of searches. When you search, you can supply not a name but a query consisting of a logical expression in which you specify the attributes that the object or objects must have. The query is called a search filter. This style of searching is sometimes called reverse lookup or content-based searching. The directory service searches for and returns the objects that satisfy the search filter.

For example, you can query the directory service to find:

all users that have the attribute "age" greater than 40 years.
all machines whose IP address starts with "192.113.50".


Packaging

The JNDI is divided into five packages:

Naming Package

The javax.naming package contains classes and interfaces for accessing naming services. It defines a Context interface, which is the core interface for looking up, binding/unbinding, renaming objects, listing the bindings. A context represents a set of bindings within a naming service that all share the same naming convention. Some naming services also provide subcontext functionality. Much like a directory in a filesystem, a subcontext is a context within a context. This hierarchical structure permits better organization of information. For naming services that support subcontexts, the Context class also provides methods for creating and destroying subcontexts.

In the JNDI, all naming and directory operations are performed relative to a context. There are no absolute roots. Therefore the JNDI defines an InitialContext, which provides a starting point for naming and directory operations. Once you have an initial context, you can use it to look up other contexts and objects. The InitialContext class is instantiated with properties that define the type of naming service in use and, for naming services that provide security, the ID and password to use when connecting.

The JNDI also defines a class hierarchy for exceptions that can be thrown in the course of performing naming and directory operations. The root of this class hierarchy is NamingException. Programs interested in dealing with a particular exception can catch the corresponding subclass of the exception. Otherwise, they should catch NamingException.

The methods of Context:
  • void bind(String stringName, Object object): Binds a name to an object. The name must not be bound to another object. All intermediate contexts must already exist. 
  • void rebind(String stringName, Object object): Binds a new name to an object bound to an old name, and unbinds the old name. All intermediate contexts must already exist. 
  • Object lookup(String stringName): Returns the object bound to the specified name.
  • void unbind(String stringName): Unbinds the object bound to the specified name. 
  • void rename(String stringOldName, String stringNewName): Changes the name to which an object was bound. 
  • NamingEnumeration<Binding> listBindings(String stringName): Returns an enumeration containing the names bound to the specified context, along with the objects and the class names of the objects bound to them. 
  • NamingEnumeration<NameClassPair> list(String stringName): Returns an enumeration containing the names bound to the specified context, along with the class names of the objects bound to them.
The difference between bind and rebind method is that bind will complain if you try to bind an already bound name to a new object while rebind wont'.

Each of these methods has a sibling that takes a Name object instead of a String object. The Name class is an interface that represents a generic name--an ordered sequence of zero or more components. It allows a program to manipulate names without having to know as much about the specific naming service in use. The Naming Systems use this interface to define the names that follow its conventions.

Directory Package

The javax.naming.directory package extends the javax.naming package to provide functionality for accessing directory services in addition to naming services. This package allows applications to retrieve associated attributes with objects stored in the directory and to search for objects using specified attributes.

The DirContext class is the heart of JNDI directory services. It behaves as a naming context by extending the Context interface.and represents a directory context. It provides all of the standard naming service functionality, and can also work with attributes and search for directory entries.

The methods of DirContext:
  • void bind( String stringName, Object object, Attributes attrs): binds a name to an object, along with associated attributes. If attrs is null, the resulting binding will have the attributes associated with obj if obj is a DirContext, and no attributes otherwise. If attrs is non-null, the resulting binding will have attrs as its attributes; any attributes associated with obj are ignored.
  • void rebind( String stringName, Object object, Attributes attributes): binds a name to an object, along with associated attributes, overwriting any existing binding. If attrs is null and obj is a DirContext, the attributes from obj are used. If attrs is null and obj is not a DirContext, any existing attributes associated with the object already bound in the directory remain unchanged. If attrs is non-null, any existing attributes associated with the object already bound in the directory are removed and attrs is associated with the named object. If obj is a DirContext and attrs is non-null, the attributes of obj are ignored.
  • DirContext createSubcontext(String stringName, Attributes attrs): creates and binds a new context, along with associated attributes. This method creates a new subcontext with the given name, binds it in the target context (that named by all but terminal atomic component of the name), and associates the supplied attributes with the newly created object. All intermediate and target contexts must already exist. If attrs is null, this method is equivalent to Context.createSubcontext().
  • Attributes getAttributes(String stringName): retrieves all of the attributes associated with a named object.
  • Attributes getAttributes(String stringName, String[] attrIds): retrieves selected attributes associated with a named object. attrIds are the identifiers of the attributes to retrieve. null indicates that all attributes should be retrieved; an empty array indicates that none should be retrieved.
  • void modifyAttributes(String stringName, int mod_op, Attributes attrs): modifies the attributes associated with a named object. The order of the modifications is not specified. Where possible, the modifications are performed atomically. mod_op is the modification operation, one of: ADD_ATTRIBUTE, REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE.
  • void modifyAttributes(String stringName, ModificationItem[] mods): modifies the attributes associated with a named object using an ordered list of modifications. The modifications are performed in the order specified. Each modification specifies a modification operation code and an attribute on which to operate. Where possible, the modifications are performed atomically.
  • NamingEnumeration<SearchResult> search(String stringName, Attributes matchingAttributes): searches in a single context for objects that contain a specified set of attributes. This method returns all the attributes of such objects. stringName is the name of the context o search.
  • NamingEnumeration<SearchResult> search(String stringName, Attributes matchingAttributes, String[] attributesToReturn): searches in a single context for objects that contain a specified set of attributes, and retrieves selected attributes. stringName is the name of the context o search.
  • NamingEnumeration<SearchResult> search(Name name, String filter,                           SearchControls cons): searches in the named context or object for entries that satisfy the given search filter. Performs the search as specified by the search controls. The format and interpretation of filter follows RFC 2254. An instance of the SearchControls class controls key aspects of the search:
SearchControls{

   int getSearchScope(); //the scope of the search to either the object (OBJECT_SCOPE), the object and the level immediately below it (ONELEVEL_SCOPE), or the object and its entire subtree (SUBTREE_SCOPE).

   long getCountLimit(); //the maximum number of entries that the search will return.

   int getTimeLimit(); //the maximum number of milliseconds that the search will run.
   String []        rgstringAttributesToReturn, //which attributes should be returned along with the entries returned by the search.

    boolean getReturningObjFlag(); //whether or not the objects bound to selected entries should to be returned along with the entries returned by the search.
   
    boolean getDerefLinkFlag();//whether or not links should be dereferenced links (or followed to their ultimate destination) during the search. A link references another directory entry and can span multiple naming systems. The underlying JNDI service provider may or may not provide support for links.
}

As with the Context class, each of the methods above also has a variant that takes a Name object rather than a String object.

The Example

The example below illustrates how to connect to a naming service, list all of the bindings, or list a specific binding. It uses the filesystem service provider, which is one of the reference JNDI service-provider implementations provided by Sun. The filesystem service provider makes the filesystem look like a naming service (which it is, in many ways -- filenames like /foo/bar/baz are names and are bound to objects like files and directories).

public class HelloWorld
import java.util.Hashtable;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
public class JNDIExample {
  public static void main(String [] rgstring) {
    try {
      // Create the initial context.  The environment information specifies the JNDI provider to use
      // and the initial URL to use (in our case, a directory in URL form -- file:///...).
      Hashtable hashtableEnvironment = new Hashtable();
      hashtableEnvironment.put(
        Context.INITIAL_CONTEXT_FACTORY, 
        "com.sun.jndi.fscontext.RefFSContextFactory"
      );
      hashtableEnvironment.put(
        Context.PROVIDER_URL, 
        "file:///"
      );
      Context context = new InitialContext(hashtableEnvironment);
      // If you provide no other command line arguments,
      // list all of the names in the specified context and
      // the objects they are bound to.
      if (rgstring.length == 0) {
        NamingEnumeration namingenumeration = context.listBindings("");
        while (namingenumeration.hasMore()) {
          Binding binding = (Binding)namingenumeration.next();
          System.out.println(
            binding.getName() + " " +
            binding.getObject()
          );
        }
      }
      // Otherwise, list the names and bindings for the
      // specified arguments.
      else {
        for (int i = 0; i < rgstring.length; i++) {
          Object object = context.lookup(rgstring[i]);
          System.out.println(
            rgstring[i] + " " +
            object
          );
        }
      }
      context.close();
    }
    catch (NamingException namingexception) {
      namingexception.printStackTrace();
    }
  }
}

To run above codes , you need to download the deprecated File System Provider implemented by Sun from: http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html


References

1. Trail: Java Naming and Directory Interface,  http://docs.oracle.com/javase/tutorial/jndi/index.html
2. JNDI Overview , http://www.javaworld.com/article/2076888/core-java/jndi-overview--part-1--an-introduction-to-naming-services.html
3. LDAP Naming Service Provider, https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-ldap.html
4. Building a Service Provider, https://docs.oracle.com/javase/jndi/tutorial/provider/
5. The original LDAP site at the University of Michigan, http://www.umich.edu/~dirsvcs/ldap/
6. OpenLDAP, http://www.openldap.org/