spring学习之注入

前面几个章节介绍了bean的定义,在一个完整的应用中,各个bean并不是相互独立的,而是一起工作的,在spring中,通过注入来把这些独立的bean串起来。

基于构造方法的注入

XML

在xml配置文件中,是通过constructor-arg标签来实现注入。
xml配置如下:




    
        
        
    

    
        
        
    

    
        
        
    


person代码:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试代码

@Test
public void test() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
    Person person1 = app.getBean("byType",Person.class);
    Person person2 = app.getBean("byName",Person.class);
    Person person3 = app.getBean("byIndex",Person.class);
    System.out.println(person1);
    System.out.println(person2);
    System.out.println(person3);
}

运行结果如下:

第一个是通过类型注入,第二个是通过名称注入,第三个是通过索引位置注入。

注解

在注解中,常用的注解是@Autowired。
MyService,MyController

@Service
public class MyService {
}
@Controller
public class MyController {
    MyService myService;

    public MyController(@Autowired MyService myService) {
        this.myService = myService;
    }
}

MyConfig

@Configuration
@ComponentScan(value="com.learn.annotation2")
public class MyConfig {

}

测试代码:

@Test
public void test(){
    ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    MyController myController=app.getBean("myController",MyController.class);
    System.out.println(myController.myService);
    System.out.println(app.getBean("myService"));
}

运行结果如下:

两次打印的地址是一样的,说明已经成功注入到myController中。如果想实现上面XML那种基本类型的注入,可以用@Bean注解,通过return new一个对象来实现。

基于setter方法的注入

XML

di.xml配置如下:




    
        
        
    


person2代码如下:

public class Person2 {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试代码:

@Test
public void test2() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
    Person2 person2 = app.getBean("person2",Person2.class);
    System.out.println(person2);
}

运行结果如下:

不同于构造器注入,setter只能通过名称注入。

ref

上面注解可以直接注入容器的对象,在XML配置中,也可以使用ref来注入。
di2.xml配置如下:



    


    
        
        
    


Persons代码如下:

public class Persons {
    Person person1;
    Person person2;

    public Persons(Person person1) {
        this.person1 = person1;
    }

    public Person getPerson2() {
        return person2;
    }

    public void setPerson2(Person person2) {
        this.person2 = person2;
    }

    @Override
    public String toString() {
        return "Persons{" +
                "person1=" + person1 +
                ", person2=" + person2 +
                '}';
    }
}

运行结果如下:

ref后面的值,是bean的标识符。

p-namespace和c-namespace

dim5.xml




    


Person3

public class Person3 {
    private String name;
    private int age;
    private String tel;

    public Person3(String tel) {
        this.tel = tel;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person3{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", tel='" + tel + '\'' +
                '}';
    }
}

测试代码:

@Test
public void test6() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di5.xml");
    Person3 person3 = app.getBean("person3", Person3.class);
    System.out.println(person3);
}

运行结果

这种写法,要引入xmlns:p和xmlns:c。p相对于property,c相对于constructor-arg。

注解

在注解中,方法名也不一定要setXXX,而且@Autowired支持直接在成员上面使用。
MyController

@Controller
public class MyController {
    @Autowired
    MyService myService;
    MyDao  myDao;

    @Autowired
    public void myDao(MyDao myDao) {
        this.myDao = myDao;
    }
}

测试代码:

@Test
public void test(){
    ApplicationContext app =  new AnnotationConfigApplicationContext(MyConfig.class);
    MyController myController=app.getBean("myController",MyController.class);
    System.out.println(myController.myService);
    System.out.println(myController.myDao);
    System.out.println(app.getBean("myService"));
    System.out.println(app.getBean("myDao"));
}

运行结果如下:

两次打印的地址是一样的,说明已经成功注入到myController中。

构造器注入和setter注入

在系统中,我们既可以用构造器注入,也可以用setter注入,甚至可以两种一起用,都可以达到我们想要的效果。
构造器注入:强依赖,大量的构造函数参数不是很优雅,无法解决循环依赖的问题,会抛出BeanCurrentlyInCreationException异常。
setter注入:可选依赖,可以重新注入。

内部类注入

di3.xml配置信息:





    
        
            
                
                
            
        
    


Outer类

public class Outer {
    private Inner inner;

    public Inner getInner() {
        return inner;
    }

    public void setInner(Inner inner) {
        this.inner = inner;
    }

    static class Inner{
        private String name;
        private int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Inner{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "Outer{" +
                "inner=" + inner +
                '}';
    }
}

测试代码

@Test
public void test4() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di3.xml");
    Outer outer = app.getBean("outer", Outer.class);
    System.out.println(outer);
}

运行结果:

内部类的bean定义,不需要id和name。因为是内部类,所以即便设置了,容器也会忽略。

集合

di4.xml配置如下:



    
        
            
                aaa
                bbb
                ccc
            
        
        
            
                
                
            
        
        
            
                aaa
                bbb
                ccc
            
        
        
            
                李四
                20
            
        
    

    
        
            
                ddd
                eee
                fff
            
        
        
            
                
                
            
        
        
            
                ddd
                eee
                fff
            
        
        
            
                
                13800138000
            
        
    


AbstractCollect和Collect

public abstract class AbstractCollect  {
    List list;
    Set set;
    Map map;
    Properties properties;

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public Set getSet() {
        return set;
    }

    public void setSet(Set set) {
        this.set = set;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "AbstractCollect{" +
                "list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}
public class Collect extends AbstractCollect{

}

测试类:

@Test
public void test5() {
    ApplicationContext app = new ClassPathXmlApplicationContext("di4.xml");
    Collect collect = app.getBean("collect", Collect.class);
    System.out.println(collect);
}

运行结果如下:

merge为true且设置了parent的时候,可以继承父类的信息。merge的时候,必须是同一类型的对象。

其他

空值的处理

如果是空字符串,以下是等同的。


    
exampleBean.setEmail("");

如果是null,以下是等同的。


    
        
    
exampleBean.setEmail(null);

depends-on和@DependsOn

当A对象包含B对象的时候,A对象初始化时,B对象必须初始完成。如果A对象没有包含B对象,也需要B对象初始化完成后,才初始化A,那可以用depends-on。
di6.xml




    
    


One和Two

public class One {
    public One(){
        System.out.println("one init");
    }
}
public class Two {
    public Two(){
        System.out.println("two init");
    }
}

测试代码

@Test
public void test7() {
    new ClassPathXmlApplicationContext("di6.xml");
}

当有depends-on="two"的时候,运行结果如下:

否则运行结果如下

说明depends-on生效了。@DependsOn这边就不做例子了。

你可能感兴趣的:(spring,java)