超详细版!!!Spring注解方式实现IOC和DI

本文详细介绍了Spring框架如何通过注解实现IoC(控制反转)和DI(依赖注入)。首先,讲解了如何配置Spring以启用注解扫描,然后展示了如何使用@Component注解注册bean,并自动推断bean的id。接着,介绍了通过@Bean注解配置工厂方法创建bean。对于DI,文章涵盖了使用@Value注入基本类型和集合,以及如何通过@Autowired实现自定义bean类型的注入。此外,还提到了其他注解如@Scope、@Lazy、@PostConstruct和@PreDestroy,以及@Controller、@Service、@Repository和@Component等组件注解的用途。最后,讨论了如何通过@Qualifier指定注入的bean。

Spring注解方式实现IOC和DI

  1. Spring注解
    Spring除了默认的使用xml配置文件的方式实现配置之外,也支持使用注解方式实现配置,这种方式效率更高,配置信息清晰,代码在哪对应的配置就在哪,方便开发阶段修改,推荐使用。
    所谓注解就是给程序看的提示信息,很多时候都用来作为轻量级配置的方式。
    关于注解的知识点,参看java基础课程中java基础加强部分的内容。

  2. Spring注解方式实现IOC

a.导入开发包

在这里插入图片描述

b.编写配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        ">
</beans>

**可以将以上头信息加入MyEclipse模版,方便后续自动生成。
c.开启包扫描
在配置文件中,开启包扫描,指定spring自动扫描哪些个包下的类。只有在指定的扫描包下的类上的IOC注解才会生效。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        ">
        <!-- 开启包扫描 -->
        <context:component-scan base-package="cn.tedu.beans"></context:component-scan>
        <!-- 
                <bean id="person" class="cn.tedu.beans.Person"></bean>        
                <bean id="cat" class="cn.tedu.beans.Cat"></bean>        
                <bean id="dog" class="cn.tedu.beans.Dog"></bean>        
         -->
</beans>

d.使用注释注册bean
在配置的包中的类上使用 @Component注解,则这个类会自动被注册为bean,使用当前类的class为< bean>的class,通常情况下使用类名首字母小写为< bean>id

案例:

package cn.tedu.beans;
import org.springframework.stereotype.Component;

@Component
public class Person{
}

e.bean的id
通常情况下注解注册bean使用类名首字母小写为bean的id,但是如果类名的第二个字母为大写则首字母保留原样.

 cn.tedu.beans.Person --> <bean id="person" class="cn.tedu.beans.Person"/>
cn.tedu.beans.PErson --> <bean id="PErson" class="cn.tedu.beans.Person"/>
cn.tedu.beans.NBA --> <bean id="NBA" class="cn.tedu.beans.NBA"/>

也可以通过在 @Component中配置value属性,明确的指定bean的id

案例:

**可以使bean类实现BeanNameAware接口,并实现其中的setBeanName方法,spring容器会在初始化bean时,调用此方法告知当前bean的id。通过这个方式可以获取bean的id信息。

 package cn.tedu.beans;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("per")
public class Person implements BeanNameAware{
        @Override
        public void setBeanName(String name) {              System.out.println("==="+this.getClass().getName()+"==="+name);
        }
}
  1. Spring注解方式实现IOC - 工厂注册bean
    Spring默认通过反射创建bean,如果某些bean没有无参构造器或创建过程非常复杂,则无法通过简单的反射创建bean,此时可以通过指定创建bean的工厂,令SpringIOC通过工厂来创建bean,从而进行注册。
    可以通过配置文件方式配置bean工厂,同样也可以通过注解配置bean工厂。
    a.配置工厂类
    工厂类必须放在包扫描目录下,且被@Component注解修饰
    b.配置工厂类中生产bean的方法
    工厂中生产bean的方法要被@Bean修饰
    则此方法会被SpringIOC调用,并将返回的对象注册为Spring的bean,默认自动推断id,也可以通过value属性手工指定id。
@Component
public class Pesron5Factory {
    @Bean("per5")
    public Person5 getInstance(){
        return new Person5("xx");
    }
}
  1. Spring注解方式实现DI
    a.导入开发包

在这里插入图片描述

b.编写配置文件,并导入context约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        ">
</beans>

c.配置开启注解实现DI选项

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.2.xsd
        ">
        <!-- 开启IOC包扫描 -->
        <context:component-scan base-package="cn.tedu.domain"/>
        <!-- 开启注解配置DI -->
        <context:annotation-config></context:annotation-config>
</beans>

d.注解方式注入spring内置支持的类型数据 - 非集合类型
spring中可以通过 @Value注解来实现spring内置支持的类型的属性的注入。

 package cn.tedu.domain;

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

@Component
public class Student {
        @Value("zs")
        private String name;
      
        @Value("19")
        private int age;
       
        @Override
        public String toString() {
                return "Student [name=" + name + ", age=" + age + "]";
        }
}

这种方式可以实现spring内置支持类型的注入,但是这种方式将注入的值写死在了代码中,后续如果希望改变注入的值,必须来修改源代码,此时可以将这些值配置到一个properties配置文件中,再在spring中进行引入。

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

e.注解方式注入spring内置支持的类型数据 - 集合类型
引入util名称空间,通过适当的util标签注册数据

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.2.xsd
        ">

        <!-- 开启IOC包扫描 -->
        <context:component-scan base-package="cn.tedu.domain"/>

        <!-- 开启注解配置DI -->
        <context:annotation-config></context:annotation-config>
        <!-- 引入Properties文件 -->
        <context:property-placeholder location="classpath:/stu.properties"/>
       
        <!-- 配置集合数据 -->
        <util:list id="l1">
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
        </util:list>
        <util:set id="s1">
                <value>111</value>
                <value>222</value>
                <value>333</value>
        </util:set>
        <util:map id="m1">
                <entry key="k1" value="v1"></entry>
                <entry key="k2" value="v2"></entry>
                <entry key="k3" value="v3"></entry>
        </util:map>
        <util:properties id="p1">
                <prop key="p1">v1</prop>
                <prop key="p2">v2</prop>
                <prop key="p3">v3</prop>
        </util:properties>
</beans>

再在类的属性中通过@Value注入赋值

 package cn.tedu.domain;

 import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Student {
        @Value("${name}")
        private String name;
        @Value("${age}")
        private int age;
       
                @Value("#{@l1}")
        private List<String> list;
        
        @Value("#{@s1}")
        private Set<String> set;
        
        @Value("#{@m1}")
        private Map<String,String> map;
        
        @Value("#{@p1}")
        private Properties prop;
       

        @Override
        public String toString() {
                return "Student [name=" + name + ", age=" + age + ", list=" + list
                               + ", set=" + set + ", map=" + map + ", prop=" + prop + "]";
        }
        
}

f.使用注解注入自定义bean类型数据:
在bean中的属性上通过@Autowired实现自定义bean类型的属性注入

代码:

package cn.tedu.domain;
 
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Student {
        @Autowired
        private Dog dog;
        
        @Autowired
        private Cat cat;
       

        @Override
        public String toString() {
                return "Student [dog="+ dog + ", cat=" + cat + "]";
        }
      
}

当Spring容器解析到@Component注解时,创建当前类的bean在spring容器中进行管理,在创建bean的过程中发现了@Autowired注解,会根据当前bean类型,寻找在spring中是否存在该类型的bean,找到直接注入,如果找不到还会检查是否有子孙类、实现类存在,如果存在唯一的则自动注入,如果还是没有找到或找到多个无法注入,则还会按照属性名对应id去查找对应的bean,如果存在则注入,如果还是没有找到则抛出异常。
也可以额外配置@Qualifier(value=“dog1”)注解强制要求按照id寻找bean,则此时会直接使用给定的id寻找bean,而不会进行基于类型的匹配。

在这里插入图片描述

**也可以使用@Resource(name=“id”)指定注入给定id的bean,但是这种方式不建议大家使用。

  1. 其他注解
    a.@Scope(value=“prototype”)
    配置修饰的类的bean是单例还是多例,如果不配置默认为单例

案例:

 package cn.tedu.domain;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class Teacher {
}

b.@Lazy
配置修饰的类的bean采用懒加载机制

案例:

 package cn.tedu.domain;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy
public class Teacher {
        public Teacher() {
                System.out.println("teacher construct..");
        }
}

c.@PostConstruct
在bean对应的类中 修饰某个方法 将该方法声明为初始化方法,对象创建之后立即执行。

d.@PreDestroy
在bean对应的类中 修饰某个方法 将该方法声明为销毁的方法,对象销毁之前调用的方法。

案例:

 package cn.tedu.beans;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class Dog {
        public Dog() {
                System.out.println("Dog...被创建出来了...");
        }
       
        @PostConstruct
        public void init(){
                System.out.println("Dog的初始化方法。。。");
        }

        @PreDestroy
        public void destory(){
                System.out.println("Dog的销毁方法。。。");
        }
}

e.@Controller @Service @Repository @Component
这四个注解的功能是完全相同的,都是用来修饰类,将类声明为Spring管理的bean的。
其中@Component一般认为是通用的注解
而@Controller用在软件分层中的控制层,一般用在web层
而@Service用在软件分层中的业务访问层,一般用在service层
而@Repository用在软件分层中的数据访问层,一般用在dao层

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张艳霞zhangyx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值