Java dependency injection standard (JSR-330) Introduction

Source: Internet
Author: User
Java dependency injection standard (JSR-330) Introduction

Reprinted by the author:

By: 88250
, Vanessa

Time: January 1, November 19, 2009

Java dependency injection standard (JSR-330, dependency injection for Java) 1.0 specification was released in October this year
. This specification is intended for dependency injection users, but does not have detailed requirements on the Implementation and configuration of the injector. Currently
, Guice
Has started to be compatible with this specification, JSR-299 (contexts and dependency injection for Java EE platform, refer to the implementation of weld
. The JSR-330 specification does not follow the JSR practice to publish the specification documentation, only released the specification API source code, this article translated the specification API documentation (javadoc) as a standard for Java dependency injection introduction.

  1. Javax. Inject

  2. @ Inject

    1. Limiter

    2. Value that can be injected

    3. Circular dependency

  3. @ Qualifier

  4. Provider

    1. Get ()

  5. @ Named

  6. @ Scope

  7. @ Singleton

 


Javax. Inject

Package javax. inject specifies a method for obtaining objects. This method is used with constructor, factory, and service locator (such as JNDI )) compared with traditional methods, these methods provide better reusability, testability, and maintainability. The processing process of this method is a well-known dependency injection, which is very valuable to most applications.

In our program, many types depend on other types. For example, a stopwatch may depend on a timesource. If some types are dependent on another type, we call these typesDependency)
. The process of searching for a dependent instance at runtime is calledAnalysis
Dependency
. If the dependent instance cannot be found, the dependency is calledNot satisfied
And the application fails to run.

When dependency injection is not used, there are several ways to parse object dependencies. The most common method is to compile code that calls the constructor directly:

Class stopwatch {

Final timesource;

Stopwatch (){

Timesource = new atomicclock (...);

}

Void start (){...}

Long Stop (){...}

}


If you need to be more flexible, we can achieve it through the factory or service locator:

Class stopwatch {

Final timesource;

Stopwatch (){

Timesource = defaulttimesource. getinstance ();

}

Void start (){...}

Long Stop (){...}

}

When using these traditional methods for dependency parsing, the programmer must

Make appropriate trade-offs. Constructor is very simple, but there are some restrictions (Object survival, Object reuse ). The factory indeed decouples customers and implementations, but requires sample code.

The service positioner further decouples customers and implementations, but reduces the type security during compilation. In addition, these three methods are not suitable for unit testing. For example, when a programmer uses a factory
Every
All products must be simulated. Remember to clean up after testing:

Void teststopwatch (){

Timesource original = defaulttimesource. getinstance ();

Defaulttimesource. setinstance (New mocktimesource ());

Try {

// Now, we can actually test stopwatch.

Stopwatch Sw = new stopwatch ();

...

} Finally {

Defaulttimesource. setinstance (original );

}

}

In reality,
Simulating a factory will lead to more sample code. Testing the simulated products and clearing them quickly won't be controlled if there are many dependencies. Worse, programmers must accurately predict
How much elasticity is needed in the future, and is responsible for his "elastic choice. If the programmer chooses the constructor method at the beginning, but then needs a more flexible method, then he has to replace all the code that calls the constructor.
If the programmer chooses the factory method too cautiously at the beginning, the result may lead to many additional sample code, introduce unnecessary complexity, and the potential problems are everywhere.

Dependency Injection
This is to solve these problems. A constructor or factory called by a programmerDependency Injector
The tool will pass the dependency to the object:

Class stopwatch {

Final timesource;

@ Inject stopwatch (timesource ){

This. timesource = timesource;

}

Void start (){...}

Long Stop (){...}

}

The injector will further pass dependencies to other Dependencies

It

Construct the entire

Object Graph
.
For example, assume that a programmer needs the injector to create
Stopwatchwidget instance:

/** GUI for a stopwatch */

Class stopwatchwidget {

@ Inject stopwatchwidget (stopwatch SW ){...}

...

}


The injector may:

  1. Search for a timesource instance
  2. Use the timesource instance to construct a stopwatch
  3. Use a stopwatch instance to construct a stopwatchwidget

This makes the code clean, making programmers feel very easy to use the dependency infrastructure.

Now, in unit testing, programmers can directly construct an object (without the injector) and pass the object to the construction of the object to be tested in the form of simulated dependencies. Programmers no longer need to configure and clean the factory or service locator for each test. This greatly simplifies our unit testing:

Void teststopwatch (){

Stopwatch Sw = new stopwatch (New mocktimesource ());

...

}

This completely reduces the complexity of unit testing and the complexity is proportional to the number of objects to be tested and their dependencies.
The javax. Inject package provides dependency injection annotations for the use of such lightweight classes.
But no dependency configuration method is introduced. The dependency configuration method depends on the implementation of the injector. Programmers only need to mark constructor, method, or field to describe their testability (the above example is constructor injection ). The dependency injector uses these annotations to identify the dependencies of a class and inject these dependencies at runtime. In addition, the injector must be ableBuild time
Verify that all dependencies are satisfied. In contrast, service locators cannot detect dependency non-conformities during build and cannot be found until the runtime.

The injector has many implementations. A injector can be configured through XML, annotation, DSL (domain protocol language), or common Java code. The injector can be generated using reflection or code. The injector generated by code in the time of compilation may not even have its own runtime description. Other injector implementations may not use code generation during compilation or runtime. A "Container" can actually be defined as a injector, but the javax. Inject package does not involve a very large concept and is designed to minimize the limitations of the injector implementation.

Please refer:

@ Inject


@ Inject

Annotation @ inject identifies the constructor, method, or field that can be injected. It can be used for static or instance members. An injected member can be modified by any access modifier (private, package-private, protected, and public. The injection sequence is the constructor, field, and method. Fields and methods of the superclass take precedence over the fields and methods of the subclass. For fields of the same class, the injection sequence is not differentiated, and the methods of the same class are the same.

The injected constructor refers to the constructor that marks @ inject and accepts 0 or multiple dependencies as real parameters. For each class, @ inject can only mark one constructor of a class:

@ Inject

Constructormodifiersopt
Simpletypename (formalparameterlistopt
) Throwsopt
Constructorbody


@ Inject is optional when only the default constructor (the access modifier is public and there are no parameters) exists. The injector calls the default constructor:

@ Injectopt

Annotationsopt

Public simpletypename () throwsopt
Constructorbody

Injected fields:

  • Marked by @ inject.
  • Not final.
  • You can use any valid name.

@ Inject fieldmodifiersopt
Type variabledeclarators;

Injection methods:

  • Marked by @ inject.
  • Not abstract.
  • No method for declaring type parameters.
  • It can return values.
  • You can use any valid name.
  • Accept 0 or multiple dependencies as real parameters.

@ Inject methodmodifiersopt
Resulttype identifier (formalparameterlistopt
)

Throwsopt
Methodbody

The injector ignores the return value of the injection method, because non-null return of the method may be used in other contexts (for example, the builder-style method chain ).

Example:

Public class car {

// Injectable Constructor

@ Inject public car (engine ){...}


// Injectable Field

@ Inject private provider <seat> seatprovider;


// Injectable package-Private Method

@ Inject void install (windshield, trunk ){...}

}

When a method is marked with @ inject and other methods marked with @ inject are overwritten, this method is only injected once for each injection request of each instance. If a method does not mark @ inject and overwrites other methods labeled @ inject, the method will not be injected.


@ Inject is required for member injection. An injected member can use any access modifier (including private ). However, due to platform or injector restrictions (such as security management or lack of reflection support), non-public members labeled @ inject may not be injected.


Limiter

Limiter
Annotation is used to mark the field or parameter that can be injected, and the field or parameter type can be used to identify the implementation to be injected. The qualifier is optional. When using a class irrelevant to the injector with @ inject, only one qualifier can be specified for one field or parameter. In the following example, the qualifier is marked in bold:

Public class car {

@ Inject private@ Leather
Provider <seat> seatprovider;


@ Inject void install (@ Tinted
Windshield windshield,

@ Big
Trunk trunk ){...}

}

If an injection method overwrites other methods, the parameters of the overwriting method do not automatically inherit the limiter from the overwriting method.

Value that can be injected

For a given type T and an optional limiter, the injector must be able to inject the user-specified class:

A. It is compatible with T assignment and

B. There is a constructor that can be injected. For example, you may use external configuration to select a t implementation. In addition, the value to be injected depends on the injector implementation and its configuration.

Circular dependency

This specification does not require in detail the detection of circular dependencies and the parsing of circular dependencies. The circular dependency between the two constructors is a very obvious problem. In addition, it is also common for the circular dependency of the field or method that can be injected, such:

Class {

@ Inject B;

}

Class B {

@ Inject a;

}

When constructing an instance of a, a simple injector may create an infinite loop: an instance of B is injected to an instance of, the second instance of a is injected to one instance of B, and the second instance of B is injected to the second instance of ,......

A conservative injector may detect this circular dependency during build and generate an error stating that the programmer can use provider <A>
Or provider <B> replaces A or B to break this circular dependency. Call the get () of the provider from the constructor or method of the injection ()
This will break the circular dependency. For method or field injection, place one side of the dependency to a specific scope (for example, Singleton scope ).
) Can also enable the loop dependency to be parsed by the injector.

Please refer:

@ Qualifier

@ Provider


@ Qualifier

Annotation @ qualifier is used to identify the annotator annotation. Anyone can define a new modifier annotation. Annotation of a modifier:

  • It is marked by @ Qualifier and @ retention (runtime), and is also marked by @ receivented.
  • You can have attributes.
  • It may be a part of a public API, just like the dependent type, rather than being a part of a public API as the type implementation.
  • If @ target is marked, there may be some usage restrictions. This specification only specifies that the modifier annotation can be used in fields and parameters, but some injector configurations may use the modifier annotation in other places (such as methods or classes.

Example:

@ Java. Lang. annotation. incluented

@ Java. Lang. annotation. Retention (runtime)

@ Javax. Inject. Qualifier

Public @ interface leather {

Color color () default color. Tan;

Public Enum color {red, black, Tan}

}


Please refer:

@ Named


Provider <t>

The interface provider is used to provide real columns of type T. Providers are generally implemented by the injector. For any injected T, you can also inject provider <t>. Injection provider <t> makes:

  • Multiple instances can be returned.
  • Instance return can be delayed or optional
  • Break the cycle dependency.
  • You can query instances in a smaller scope in an instance with a known scope.

Example:


Class car {

@ Inject car (provider <seat> seatprovider ){

Seat driver = seatprovider. Get ();

Seat passenger = seatprovider. Get ();

...

}

}


Get ()

It is used to provide a fully constructed instance of type T.

Exception throw: runtimeexception -- this exception is thrown when the injector encounters an error when providing the instance. For example, if an injected member t throws an exception, the injector packs the exception and sends it to the get () caller. The caller should not try to handle this type of exception, because different injector implementations behave differently. Even the same injector may behave differently due to different configurations.


@ Named

String-based Limiter
.

Example:

Public class car {

@ Inject @ named ("driver") seat driverseat;

@ Inject @ named ("passenger") seat passengerseat;

...

}



@ Scope

Annotation @ scope is used to identify the scope annotation. A scope annotation is identified on a class that contains an injection constructor and used to control how instances of this type are reused by the injector. By default, if no scope annotation is identified, the injector creates (through the injection constructor) new instances for each injection and does not reuse existing instances. If multiple threads can access an instance in the same scope, the implementation of this instance should be thread-safe. The implementation of the scope is completed by the injector.

In the following example, the scope annotation @ Singleton ensures that there is always only one log instance:

@ Singleton

Class log {

Void log (string message ){...}

}

When more than one scope annotation or scope annotation not supported by the injector is used on the same class, the injector generates an error.

A scope annotation:

  • Marked by @ scope and @ retention (runtime), which is also marked by @ receivented.
  • Attribute should not be included.
  • It should not be marked by @ inherited, so the scope is irrelevant to the inheritance implementation (orthogonal.
  • If @ target is marked, there may be some usage restrictions. This specification only specifies that the scope annotation can be used in the class, but some injector configurations may use the scope annotation in other places (such as factory method return.

Example:

@ Java. Lang. annotation. incluented

@ Java. Lang. annotation. Retention (runtime)

@ Javax. Inject. Scope

Public @ interface requestscoped {}

Use @ Scope
To identify a scope annotation helps the injector to detect the situation where programmers use the scope annotation but forget to configure the scope. A conservative injector should generate an error rather than apply this scope.

Please refer:

@ Singleton


@ Singleton

Annotation @ Singleton identifies the type that the injector only instantiates once. The annotation cannot be inherited.

Please refer:

@ Scope

 

 

Well-formed

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.