Spring依赖注入三种方式及分析

按照Spring官网来说spring存在两种注入方式

1:构造函数注入
2:Setter注入

构造函数注入

@Component
public class ServiceB {

    public  ServiceB(){
        System.out.println("B 调用了构造函数");
    }
}


@Component
public class ServiceA {

    private ServiceB serviceB;

    public ServiceA(ServiceB serviceB) {
        System.out.println("serviceB 被注入到ServiceA中");
        this.serviceB = serviceB;
    }
}

最后输出结果:

B 调用了构造函数
serviceB 被注入到ServiceA中

构造函数注入方式前提条件是注入对象(ServiceA)和被注入对象(ServiceB)都交由Spring托管。
当存在多个构造函数时,Spring默认选用无参构造函数创建Bean,导致构造函数注入不成功。

@Component
public class ServiceA {

    private ServiceB serviceB;


    public  ServiceA(){
        System.out.println("ServiceA 构造函数创建!!!");
    }

    public ServiceA(ServiceB serviceB) {
        System.out.println("serviceB 被注入到ServiceA中");
        this.serviceB = serviceB;
    }
}



@Component
public class ServiceB {

    public  ServiceB(){
        System.out.println("B 调用了构造函数");
    }
}

输出结果

ServiceA 构造函数创建!!!
B 调用了构造函数

2.Setter注入

@Component
public class ServiceA {

    private ServiceB serviceB;


    public ServiceA() {
        System.out.println("ServiceA 构造函数创建!!!");
    }


    @Autowired
    public void setServiceB(ServiceB serviceB) {
        System.out.println("serviceB 注入");
        this.serviceB = serviceB;
    }
}


@Component
public class ServiceB {

    public  ServiceB(){
        System.out.println("B 调用了构造函数");
    }
}

输出结果

ServiceA 构造函数创建!!!
B 调用了构造函数
serviceB 注入

@Autowired注解于方法上。
可能存在疑问:@Autowired注解于方法上和注解于字段上有什么区别?
我理解上注入方法和注入字段都可以叫setter注入。

  • 注解在方法上最终是调用Method.invoke(object,args)调用setXXX方法注入。
  • 注解在字段上最终调用Filed.set(XXXX);

3.@Lookup 方法注入
对于@Lookup修饰的方法,有相对应的标准

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

public|protected要求方法必须是可以被子类重写和调用的
abstract可选,如果是抽象方法,CGLIB的动态代理类就会实现这个方法,如果不是抽象方法,就会覆盖这个方法
return-type是非单例的类型
no-arguments不允许有参数

这个注解有点鸡肋,目前好像还没有用到。包括一些常用的三方包里面也没有用到。当一个单例类(Singleton)
注入一个原型类(prototype)时,单例类里面所有的方法都是调用同一个原型类(prototype)实例.....大概等同于

@Component
public class ServiceA {

    @Autowired
    private ServiceB serviceB;

    public int add(int i) {
        return serviceB.add(i);
    }
}


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ServiceB {

    int i=1;
    
    public int add(int j) {
        return i= i + j;
    }
}


ServiceA serviceA = context.getBean(ServiceA.class);
System.out.print(serviceA.add(1));
System.out.print(serviceA.add(2));
System.out.print(serviceA.add(3));
调用结果:
2 
4
7

想要add()方法每次调用的对象实例都不一样就要用到@Lookup。

@Component
public class ServiceA {
    public ServiceA() {
        System.out.println("ServiceA 构造函数创建!!!");
    }
    
    @Lookup
    public ServiceB createServiceB() {
        return null;
    }
    
    public int add(int i) {
        ServiceB serviceB = createServiceB();
        return serviceB.add(i);
    }
}


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ServiceB {

    int i=1;

    public ServiceB() {
        System.out.println("B 调用了构造函数");
    }


    public int add(int j) {
        return i= i + j;
    }
}

ServiceA serviceA = context.getBean(ServiceA.class);
System.out.print(serviceA.add(1));
System.out.print(serviceA.add(2));
System.out.print(serviceA.add(3));
调用结果:
B 调用了构造函数
2
B 调用了构造函数
3
B 调用了构造函数
4

调用@Lookup标识的方法约等于直接从上下文中直接调用getBean()方法。


SamZhang
0 声望0 粉丝