[Spring] Games

Brief introduction

Our writing program, there are between the various categories dependent, dependent on the class of the instance of the need to manually re-assigned to it. Since we are automatically managed by the IoC container Bean, each use need to manage such dependencies too cumbersome.

So there by way of the configuration file to automatically inject dependent bean.

spring assembly 3 xml装配ways: java装配, 自动装配, .

Compared to xml装配recommend it is to use java装配.

Commonly used 自动装配to reduce the configuration file.

Automated assembly

From the perspective of two spring assembly automatically:

  • 组件扫描: Spring bean will automatically find the application context created.
  • 自动装配: Spring assembly automatically satisfy the bean.

Project structure

.
├── build.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── yww/
    │   │           ├── Main.java
    │   │           ├── Message.java
    │   │           ├── ReaderConfig.java
    │   │           └── Reader.java
    │   └── resources/
    │       └── beans.xml
    └── test/
        ├── java/
        │   └── com/
        │       └── yww/
        │           └── MainTest.java
        └── resources/

Code

build.gradleProject build configuration.

Part of the comment is the use of plug-ins and direct gradle runcommand to run the project. jar{}Section configuration, as can be packaged with a javacommand to run jarthe package. (Note that you need to specify the full name of a good master class)

plugins {
    id 'java'
    // id 'application'
}

// mainClassName = 'com.yww.Main'
group 'com.yww'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

ext{
    springVersion = '5.2.0.RELEASE'
}

dependencies {
    compile "org.springframework:spring-core:$springVersion"
    compile "org.springframework:spring-context:$springVersion"
    compile "org.springframework:spring-beans:$springVersion"
    compile "org.springframework:spring-expression:$springVersion"
    compile "org.springframework:spring-aop:$springVersion"
    compile "org.springframework:spring-aspects:$springVersion"

    testCompile "junit:junit:4.12"
    testCompile "org.springframework:spring-test:$springVersion"
}

jar {
    from {
        configurations.runtime.collect{zipTree(it)}
    }
    manifest {
        attributes 'Main-Class': 'com.yww.Main'
    }
}

Message.javaBy using @Componentannotations, when the component scanning, registration bean.

@ValueNotes straightforward assignment. Bean configuration is different from the xml configuration file so cumbersome.

package com.yww;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Message {
    @Value("---hello world---")
    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = "this mssage is : " + msg;
    }

}

Reader.javaIt depends on the Message.javause of @Autowiredinjection Messagethe bean into Readerthe.

Here can be @Autowiredwritten on the member variables can also be written in the constructor, choose one of the two can be. (Constructor automatically connect can do some other operations only)

package com.yww;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Reader {
//    @Autowired
    private Message msg;

    @Autowired
    public Reader(Message msg){
        this.msg = msg;
    }

    public void print(){
        System.out.println(msg.getMsg());
    }

}

ReaderConfig.javaProfile, mainly when used in acquiring application context, such a complete open configuration provided therein. Its class name any. Here is the main component scans open the default package with the same name @Componentetc. annotation registered as a bean.

Traditionally, we can do some configuration work here, such as setting the initial value, or how to assemble. For convenience, the initial value used in the previous @Valueset.

package com.yww;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class ReaderConfig {

    // 可以在配置文件中设置初始值
    // 为了方便直接,就在Message的成员上使用@Value设置了值。
//    @Bean
//    public Message message(){
//        Message message = new Message();
//        message.setMsg("---hi---");
//        return message;
//    }
}

Main.javaThe main function, for starting applications. We show here how to get to a dependent relationship, and in accordance with good bean automatic assembly.

Is different from the web application, app need to have a primary function to start the application, conventional web applications packaged into war will be loaded into the tomcat, but spring bootthe web application can also have a main function to start web application.

Code comment section is to use xml配置, demonstrate how to obtain the bean.

package com.yww;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args){
        // xml配置(beans.xml)
//        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//        Message msg = (Message) context.getBean("msg1");
//        System.out.println(msg.getMsg());

        // java配置(ReaderConfig.java) + 获取组件扫描到的bean
        // 测试文件AppTest.java中,可以通过注解@ContextConfiguration加载配置文件上下文,方便使用@Autowired注解获取Bean。
        ApplicationContext context = new AnnotationConfigApplicationContext(com.yww.ReaderConfig.class);
        Reader reader = (Reader) context.getBean(Reader.class);
        reader.print();
    }
}

The last remaining test file MainTest.java, not much say in here, but you can use @ContextConfigurationannotation get the context of the bean, the use of @Autowiredautomatic injection bean, convenient test.

run

Because the sake of simplicity, the project is non-web project, few posts to explain this package and run. (Web projects easily by adding warplug-ins and gradle buildpackaging)

The method of operation to try out a few:

  • Method 1: Use idea run directly mainclass can also be run the test class MainTest.java.

  • Method 2: Use gradle, need to build.gradlefile, add the plug-in applicationand set good name of the main function mainClassName. Finally, the project root directory ( build.gradleexecute the command the same directory):
gradle run

Problem

In the 非webapplication, you will find a problem, not by @Autowiredacquiring the bean, which is due to non-web applications not know bean, did not provide the appropriate annotation to deal only through ApplicationContextcontext acquisition bean application. And between the bean can be achieved through @Autowiredacquired.

java assembly

In many cases, automated configuration is the recommended way to scan through components and automated assembly. But if you want a third-party library to assemble their applications can not use @Componentannotations to automate the assembly.

To explicitly configured bean, can be used in the configuration file @Beanto obtain.

// src/main/java/com/yww/ReaderConfig.java
// ...
@Bean
public Message message(){
    Message message = new Message();
    message.setMsg("---hi---");
    return message;
}
// ...

The use of automatic assembly, the same can not create more than one type of bean.

Bean renamed

The default bean's ID and @Beanthe same annotation method name.

Available nameparameter settings other names.

@Bean(name="msgX")

Without using the scan assembly configuration

If you do not use the component scanned, how to find a configuration of another configuration, or bean?

At this time, you may be used @Importto import that class.

package com.yww;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({MessageConfig.class})
public class ReaderConfig {

    // 可以在配置文件中设置初始值
    // 为了方便直接,就在Message的成员上使用@Value设置了值。
//    @Bean
//    @Bean(name="msgX")
//    public Message message(){
//        Message message = new Message();
//        message.setMsg("---hi---");
//        return message;
//    }

    // 这个bean传入的名称可以任意.
    // 但如果在同一个类里声明了名称,像上面那样指定了名词,这里的参数名也必须相同。
    @Bean
    public Reader reader(Message msg){
        System.out.println(msg.getMsg());
        msg.setMsg("---hello---");
        return new Reader(msg);
    }

}

Wherein, another bean imported java配置file as follows.

// src/main/java/com/yww/MessageConfig.java
package com.yww;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MessageConfig {

    @Bean
    public Message message(){
        return new Message();
    }
}

xml Assembly

  • gradle app is xml配置placed src/main/resources/in the directory.
  • the web xml配置on the web/WEB-INF/directory, you need web.xmlconfiguration <context-param>.

Shaped configuration such as the following.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/

    <bean id="msg1" class="com.yww.Message">
        <property name="msg" value="hello world"/>
    </bean>

</beans>

If not given id, will be named by the fully qualified class name, the bean will be named herein com.yww.Message#0, #0it is a count of the same type of other bean.

Other settings

Because not recommended xml配置, it is just a simple configuration in which a note of this.

There are a lot of configuration c-命名空间, p-命名空间to replace the complicated labels.

  • Injected bean reference configuration, injection strings, numbers, lists. (<Constructor-arg>)
  • Xml configuration using <bean> JavaConfig import configuration.
  • <beans>Of profileproperty.
  • <jdbc><jee:jndi-lookup>
  • <beans>Nesting <beans>.

Advanced Assembly

More configuration, to achieve more control assembly.

Profile

Usually we need to configure different environments, such as: test environment using the embedded database h2, the production environment using the jndiacquired database.

(Starting from spring4) @Profileis also based on @Conditionalimplementation.

Configuration settings

You can use @Profileannotations in or 方法on, to generate Bean. (As used herein, JavaConfigthe configuration can also be used xmlto configure)

package com.yww;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
@PropertySource("application.properties")
public class ReaderConfig {

    @Bean
    @Profile("dev")
    public Message message1(){
        Message message = new Message();
        message.setMsg("---hi---1");
        return message;
    }

    @Bean
    @Profile("prod")
    public Message message2(){
        Message message = new Message();
        message.setMsg("---hi---2");
        return message;
    }
}

@PropertySourceImport the configuration file.

Active configuration

Determine which profile is activated by two properties spring.profiles.activeand spring.profiles.default.

If you set up active, use this value to determine which profile is activated. If not set active, use defaultOK. If you did not set, it will only create a profile does not define the bean.

#src/main/resources/application.properties
spring.profiles.default=dev
spring.profiles.active=prod

In the test class, you can be used @ActiveProfiles("dev")conveniently activated configuration.

Otherwise

There are many ways to set properties:

  • DispatcherServlet initialization parameters.
  • Web application context parameter.
  • JNDI entries.
  • Environment variables.
  • JVM system properties.
  • The integrated test class, using @ActiveProfiles annotation setting.

Embodiment, web.xmlconfiguration.

    <!-- ... -->
    <context-param>
        <param-name>spring.profiles.default</param-name>
        <param-value>dev</param-value>
    </context-param>
    <!-- ... -->

Appendix: The configuration file is how related?

How to find the program .propertiesfile?

In app project, we passed @PropertySourcenotes to JavaConfig class, set the .propertiespath to the configuration file.

In gradle project, the configuration file in src/main/resources/path, can also be placed in this file in the directory folder. Such as: src/main/resources/demo/app.propertiessetting @PropertySource("demo/app.properties").

In a web project, spring web has a profile set up, no @PropertySourceconfiguration.

Conditioned Bean

If you want to achieve will be created after a bean contains only when creating a specific library in the classpath of the application, or if you want a bean will be created only when a particular bean declaration after another, or set a specific environment variable a bean.

By @Conditionalannotation, which can be used with @Beanthe method of annotations. If the condition is created bean is true, otherwise the bean will be ignored.

Conditioned bean is spring bootto achieve the principles of automatic assembly.

Examples

When the configuration file contains a "reader" value, create bean.

Directory Structure

.
├── build.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── yww/
    │   │           ├── Main.java
    │   │           ├── Message.java
    │   │           ├── ReaderConfig.java
    │   │           ├── ReaderExistsCondition.java
    │   │           └── Reader.java
    │   └── resources/
    │       ├── application.properties
    └── test/
        ├── java/
        │   └── com/
        │       └── yww/
        │           └── MainTest.java
        └── resources/

Key Code

Cancel the Reader.javaclass @Componentnotes, convenient here to create conditions of use of the Reader mode of bean.

Conditions set for ReaderExistsCondition.javathis class inherits the interface Condition.

package com.yww;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
@PropertySource("application.properties")
public class ReaderConfig {

    @Bean
    public Message message1(){
        Message message = new Message();
        message.setMsg("---hi---");
        return message;
    }

    @Bean
    @Conditional(ReaderExistsCondition.class)
    public Reader reader(Message message){
        return new Reader(message);
    }
}

The conditions set for, to find out whether there is named from the configuration file readerconfiguration properties, if the method matchesreturns true, which will be set up to create conditions of bean.

package com.yww;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ReaderExistsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment env = context.getEnvironment();
        return env.containsProperty("reader");
    }

}

Appendix: Interface Condition

ConditionInterface source code below, contains only one matchesmethod, if the method returns trueThat will satisfy the conditions created bean, falsethat is not created.

@FunctionalInterface
public interface Condition {

    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

ConditionContextYou can check the interface Bean, environment variables, resources and classes.

AnnotatedTypeMetadataInterface can be checked with @Beana method annotated what other notes.

Ambiguity automatic assembly process

When a plurality of the same type bean is created, the component can not be selected by the scan assembly.

spring throws NoUniqueBeanDefinitionException.

Solution

There are two processing methods:

  • In @Componentor @Beanon the use of @Primaryannotations, in the face of ambiguity, select the preferred bean.
  • In @Autowiredor @Injecton the use of @Qualifierdefining the bean to be injected ID. When the notes to @Component, or @Beanwhen, it is to create your own qualifier (similar renamed the bean ID).

@QualifierDefining a name tag provided similar to bean, spring loading will meet bean tag.

To set a plurality of tags, you can define your own annotated @Qualifierinterface, as with a custom label annotation is defined. (Java 8 allows the definition to add annotations @Repeatableto achieve repeat the comments, but Spring is @Qualifiernot added to this repeat annotations.)

Annex: byName and byType

In general, although the bean and injection parameters were created not the same (here the bean name message1and parameter name message), but spring will be byTypea way to find the same type of bean assembled.

package com.yww;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
public class ReaderConfig {

    @Bean
    public Message message1(){
        Message message = new Message();
        message.setMsg("---hi---1");
        return message;
    }

    @Bean
    public Reader reader(Message message){
        return new Reader(message);
    }
}

But when there are multiple different types of bean, you can not rely on byTypeto find the corresponding bean, by changing the parameters passed name (here use parameter names message2), the use of byNamedesignated bean.

package com.yww;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan
public class ReaderConfig {

    @Bean
    public Message message1(){
        Message message = new Message();
        message.setMsg("---hi---1");
        return message;
    }

    @Bean
    public Message message2(){
        Message message = new Message();
        message.setMsg("---hi---2");
        return message;
    }

    @Bean
    public Reader reader(Message message2){
        return new Reader(message2);
    }
}

External value injection

Environmental values ​​can be obtained in three ways:

  • Implantation using Environment.
  • Placeholder property (property placeholder).
  • Spring expression language SpEL.
#src/main/resources/application.properties
info.message=this is a message.
info.counter=10

Environment:

import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;

@Component
@PropertySource("application.properties")
public class Message {

    @Autowired
    Environment env;

    public void print(){
        String msgStr = env.getProperty("info.message", "this is a msg");
        int msgInt = env.getProperty("info.counter", Integer.class, 30);
    }

}

Property placeholder:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@PropertySource("application.properties")
public class Message {
    @Value("${info.message}")
    private String msg;
}

Spring EL:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@PropertySource("application.properties")
public class Message {
    @Value("#{systemProperties['info.message']}")
    private String msg;
}

Guess you like

Origin www.cnblogs.com/maplesnow/p/11628735.html