Spring注解及依赖注入

spring注解.png

spring注解.pdf

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    
     <!--扫描com.woniu包及子包下的所有的类上是否有注解-->
    <context:component-scan base-package="com.woniu" />
    
</beans>

1.回顾

  • Spring入门

    • Spring框架定义

Spring是分层JavaEE应用企业轻量级开源框架产品
两大核心特性:  IOC和AOP

Spring各层提供解决方案:  SpringMVC ,SpringJDBC,管理业务层事务,日志
SSM组合:

image-20220616095501010

  • 什么是IOC与优点

IOC -  控制反转
|-对象的调用者不用自己去创建该对象,而是由IOC容器统一提供,这种方式就称为控制反转

降低程序间的耦合
  • Spring实现IOC入门示例操作步骤

a. 依赖: spring-context

b. 添加spring核心配置文件 - applicationContext.xml    
  <beans>
        <bean id=""  class="">
        </bean>
  </beans>

c. 创建工厂对象
  BeanFactory  -Spring顶层工厂
      |-子接口ApplicationContext 工厂对象
  new ClassPathXMLApplcationContext(".xml")

d. 通过工厂对象获取bean对象   getBean("name")      
  • 上次作业 自定义IOC工厂练习

指定需要扫描注解的包
com.woniu.bean
  |-类
@Component 元件,部件  


已知一个包com.woniu.bean下分别有Tiger、Lion、Elephant三个Java源文件,请据此实现以下功能: [选做]

(1)自定义一个名为Component的注解,要求该注解只能用于类且代码运行时该注解依然有效;

(2)为Tiger和 Lion类添加Component注解(注:只写出类的结构和构造方法即可)

(3)在Application类中定义静态代码块,该代码块可自动将有Component注解修饰的类创建对象,并
放在Map集合中;

(4)  然后定义一个名为getBean的static方法,要求传入String beanName返回该名称对应的bean实例对象,如果没有找到
该beanName对应的实例对象,则引发NoSuchBeanDefinitionException自定义异常,
并提示“No qualifying bean avaliable !”    
pack.name=com.woniu.bean

注解类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
   String value() default "";
}

Bean实体类:

@Component("ele")
public class Elephant {
   public Elephant() {
       System.out.println("Elephant创建了...");
   }
}
@Component
public class Lion {

   public Lion() {
       System.out.println("Lion创建...");
   }
}
@Component("tiger")
public class Tiger {
   public Tiger() {
       System.out.println("Tiger创建了...");
   }
}

工厂类Application

/**
* 工厂类
*/
public class Application {
   private static Map<String,Object> map = new HashMap<>();

   static {
       try {
       /*
         该代码块可自动将有Component注解修饰的类创建对象,
          并放在Map集合中
        */
           Properties props = new Properties();
           InputStream inStream = Application.class.getClassLoader().getResourceAsStream("pack.properties");
           props.load(inStream);
           inStream.close();
           //获取配置包名
           String packName = props.getProperty("pack.name");

           //获取指定包下所有class文件 - 获取当前应用程序的class文件的根路径
           File classRootPath  =new File(Application.class.getResource("/").toURI());

           //将包名修改为 路径名
           String packPath = packName.replace(".","\\");
           File targetPath = new File(classRootPath.getPath()+"\\"+packPath);
           File[] classFile  = targetPath.listFiles(); //获取bean包下的所有类文件
           for (File file : classFile) {
               String fileName = file.getName();
               String className = fileName.replace(".class","");
               Class clazz = Class.forName(packName+"."+className); //获取类名对应的Class对象
               if(clazz.isAnnotationPresent(Component.class)){
                   //获取类上的注解对象信息
                   Component component = (Component) clazz.getDeclaredAnnotation(Component.class);
                   String beanName = component.value();
                   if("".equals(beanName)){
                       beanName = className.substring(0,1).toLowerCase()+className.substring(1);
                   }
                   //将bean对象存放容器中
                   map.put(beanName,clazz.newInstance());
               }
           }

       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   public static Object getBean(String name){
       Object bean = map.get(name);
       if(bean==null){
           throw  new NoSuchBeanDefinitionException("No qualifying bean avaliable!");
       }
       return bean;
   }

   public static void main(String[] args) {
       Tiger tiger =(Tiger)Application.getBean("tiger");
       System.out.println(tiger);
       Lion lion =(Lion)Application.getBean("lion");
       System.out.println(lion);
        Elephant elephant =(Elephant) Application.getBean("ele");
        System.out.println(elephant);
   }
}

2.Spring入门-补充

2-1 Spring工厂类结构体系

BeanFactory属于Spring顶层工厂接口  [平时开发不使用]

  |- ApplicationContext工厂接口  --常用的

ClassPathXmlApplicationContext:
   |-它是从类的根路径下加载配置文件,推荐使用这种    /resources 目录
   
FileSystemXmlApplicationContext:  [一般不使用]
   |-它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
   
AnnotationConfigApplicationContext: 基于注解配置来创建的工厂对象
   |-当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解

2-2 BeanFactory与AppicationContext区别

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口

区别:

applcationContext具有BeanFactory不具备功能:
a. AOP特性
b. web应用功能支持
c. 加载Bean的区别

细节区别:

BeanFactroy采用的是延迟加载形式来注入Bean
  |-启动程序,读取配置文件,但并不创建对象,并存入容器
  |-只有在访问对象时,才去创建
 

applcationContext 采用的是即时加载,也就是在启动程序时,读取配置,创建对象,并存入容器

3 Spring-IOC-2

3-1 Bean的管理

a.bean的作用域范围

bean的scope属性用于指定bean的范围

 |-singleton  单例  [默认值]

 |-prototype 多例

1、singleton :默认值,单例的.

2、prototype :多例的.

3、request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中

4、session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.

5、global session :WEB 项目中,应用在 Portlet 环境 .如果没有 Portlet 环境那么 globalSession 相当于 session.
public void testAddUser(){
   //创建工厂Bean对象
   //BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

   ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
   System.out.println("==============================================================");
   UserService userService1 = (UserService)ac.getBean("userService");
   UserService userService2 = (UserService)ac.getBean("userService");

   System.out.println(userService1==userService2);

   userService1.addUser();
}

b.bean生命周期  - 重点

分为单例与多例讨论:
Singleton单例:
一个应用只有一个对象的实例。它的作用范围就是整个应用

出生: 创建容器时
活着: 容器存在,对象存在
死亡: 容器销毁时,对象消失

prototype多例:

出生: 当使用对象时,创建新的对象实例
活着: 只要对象在使用中,就一直活着
死亡: 对象不再使用时,由GC垃圾回收器来回收
|-不是由容器来维护和管理

示例:

/**
 * 用户业务实现类
 */
public class UserServiceImpl implements UserService {
    //创建数据层对象
    private UserDao userDao;

    public void addUser() {
        //执行数据操作方法
        userDao.save();
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void init(){
        System.out.println("userService对象初始化...");
    }

    public void destroy(){
        System.out.println("userService对象销毁....");
    }
}

applicationContext.xml

<?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/spring-beans.xsd">

    <bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" scope="prototype"/>

    <bean id="userService"  class="com.woniu.service.impl.UserServiceImpl"
          scope="prototype" init-method="init" destroy-method="destroy">
        <!--依赖注入 使用setter -->
        <property name="userDao" ref="userDao" />
    </bean>
</beans>

测试业务类:

/**
 * 业务测试类 --模拟表示层
 */
public class UserServiceTest {

    @Test
    public void testAddUser(){
        //创建工厂Bean对象
       //BeanFactory ac = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("==============================================================");
        UserService userService1 = (UserService)ac.getBean("userService");
       // UserService userService2 = (UserService)ac.getBean("userService");
       //   System.out.println(userService1==userService2);

        userService1.addUser();

        //关闭容器
        ac.close();
    }
}

c.实例化bean的三种方式 -- 了解

方式一: 使用默认构造器 -- 常用

<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl"/>

方式二: 静态工厂方式创建方式

<!--bean的id标识的对象由StaticFactory 工厂类中的静态方法getUserDao()来提供-->
    <bean id="userDao" class="com.woniu.factory.StaticFactory" factory-method="getUserDao"/>

示例代码:

/**
 * 静态工厂类
 */
public class StaticFactory {

    /**
     *   静态工厂方法
     * @return
     */
    public static UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

方式三: 实例工厂创建对象方式

/**
 * 实例工厂类
 */
public class InstanceFactory {

    /**
     *   实例工厂方法
     * @return
     */
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
 <!--创建实例工厂Bean对象-->
    <bean id="instanceFactoryBean" class="com.woniu.factory.InstanceFactory" />

    <!--指定实例的工厂bean对象及工厂方法,创建UserDao对象-->
    <bean id="userDao" factory-bean="instanceFactoryBean" factory-method="getUserDao" />

小结:

方式二和方式三适用于,引用第三方jar中的类来创建对象时,如果该类中没有默认无参构造器时可以使用

还有像Calendar这样类似的抽象类,不能直接通过构造器创建对象,但是提供了静态方法创建实例
JDK--> java.util.Calendar类 
 <bean id="cal" class="java.util.Calendar" factory-method="getInstance" />

3-2 依赖注入

DI - Dependency Injection 依赖注入 - IOC的实现方式

比如: UserServiceImpl --> UserDao对象

依赖注入的方式:

(1). setter注入

public class UserServiceImpl implements UserService {
    //创建数据层对象
    private UserDao userDao;
    
    public UserDao getUserDao() {
        return userDao;
    }
    
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    
    ...
}

配置setter的依赖注入:

<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />

<bean id="userService"  class="com.woniu.service.impl.UserServiceImpl">
        <!--依赖注入 使用setter -->
        <property name="userDao" ref="userDao" />
</bean>

(2) 构造器注入

public class UserServiceImpl implements UserService {
    //创建数据层对象
    private UserDao userDao;

    private String name;
    private Integer age;
    private Date birthday;

    public UserServiceImpl() {
    }

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserServiceImpl(String name, Integer age, Date birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }


涉及的标签:
  constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称 用这个来找给谁赋值
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean

配置构造器注入:

 <bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />

    <bean id="userService" class="com.woniu.service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao" />
    </bean>
-----------------------------------------------------------------
  <bean id="now" class="java.util.Date" />

    <bean id="userService" class="com.woniu.service.impl.UserServiceImpl">
        <!--<constructor-arg name="userDao" ref="userDao" />-->
        <constructor-arg index="0" value="Jack" />
        <constructor-arg index="1" value="20" />
        <constructor-arg name="birthday" ref="now" />
    </bean>

(3) p和c命名空间注入

添加p命名空间-- 本质上也是setter注入

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
 <bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />

    <bean id="userService" class="com.woniu.service.impl.UserServiceImpl" p:userDao-ref="userDao">
    </bean>

c-命名空间 -- Constructor注入的简写

   <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"> 
       
   <bean id="now" class="java.util.Date" />

    <bean id="userService" class="com.woniu.service.impl.UserServiceImpl" c:_0="Tom" c:_1="21" c:_2-ref="now">
    </bean>

(4) 集合属性的注入 - [了解]

Array,List为例

如果我们的Bean类属性是数组或集合 [List, set, Map,Properties]


public class Bean {
    private String[] arr;
    private List<String> strList;
    private List<User> userList;
    private Map<String,User> map;

    public void print(){
        System.out.println("--------------------------Array--------------------");
        for(String s : arr){
            System.out.println(s);
        }
        System.out.println("--------------------------StrList--------------------");
        for(String s : strList){
            System.out.println(s);
        }
        System.out.println("----------------UserList------------------------");
        for(User u : userList){
            System.out.println(u);
        }
    }
    
    ...
}

配置注入:

<bean id="userBean" class="com.woniu.entity.User">
    <property name="name" value="Mike" />
    <property name="age" value="22" />
</bean>


<bean id="bean" class="com.woniu.bean.Bean">
    <!--方式一: 为数组属性注入值-->
    <!--<property name="arr" value="aaa,bbb,ccc" />-->
    <!--方式二: 使用array    -->
    <property name="arr">
        <array>
            <value>xxx</value>
            <value>yyy</value>
            <value>zzz</value>
        </array>
    </property>
    <property name="strList">
        <list>
            <value>111</value>
            <value>222</value>
            <value>333</value>
        </list>
    </property>
    <property name="userList">
        <list>
            <bean class="com.woniu.entity.User">
                <property name="name" value="Jack" />
                <property name="age" value="24" />
            </bean>
            <ref bean="userBean" />
            <ref bean="userBean" />
        </list>
    </property>
</bean>

4. Spring - 注解

4-1 基于注解实现springIOC

(1) Spring注解的背景

Spring1.x 时代,基于XML配置时代,缺点:

xml文件将会十分庞大,拆分后xml会非常多,可读性与可维护性变得很低

.java文件和.xml文件之间不断切换,影响开发效率

为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性

(2) 常用的IOC配置-注解

前提: 要使用Spring注解完成IOC配置,首先要开启Spring自动检测bean的配置。

或者说是: 开启Spring注解扫描的功能

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    
     <!--扫描com.woniu包及子包下的所有的类上是否有注解-->
    <context:component-scan base-package="com.woniu" />
    
</beans>

@Component 组件注解


//如果不指定Component注解的成员属性值,则默认使用类名首字母小写作为bean的名称
@Component
public class UserDaoImpl implements UserDao {
    ...
}
等价于xml:
<bean id="userDao" class="com.woniu.dao.impl.UserDaoImpl" />

@Resource 属性注入注解

/**
 * 用户业务实现类
 */
@Component("userService")
public class UserServiceImpl implements UserService {
    //创建数据层对象
    @Resource(name="userDaoImpl")  //注解作用是将容器中的name为userDao对象注入到属性userDao
    private UserDao userDao;
    
    ...
}

(3) 常用的其他几个注解

效果等同于 @Component  :语义注解

  • @Controller @Service @Repository 分层语义注解

这三个注解都是针对第一个的衍生注解,他们的作用级属性都是一模一样。不过提供了更加明确的语义化。
@Controller:一般用于表现层的注解。即SpringMVC中
@Service:一般用于业务层的注解。
@Repository:一般用于持久层的注解

-------------------------------如果创建bean对象不属于三层中的任一层,则使用@Component注解
  • @Autowired 自动装配

自动按类型进行注入,可以省略setter
当有多个同类型的bean相匹配时,则默认根据属性名进行注入,也可以指定@Qualifier注解指定bean的名称进入注入,否则会报错
另外,可以指定成员属性required=false ,避免因找不到bean而报错,使用null值
  • @Autowired与@Resurce区别 ?

相当于:<property name="" ref="">

区别1:
    @Autowired [常用]  - 默认按照属性类型注入
    @Resource -默认按属性名称注入 -- name="xxx"

区别2:
    @Autowired 属于Spring框架提供
    @Resource由javaEE提供的注解

共同点:
  使用时,都可以将类中的 setter访问器省略
  • @Qualifier 指定容器中的bean名称进行注入

      在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用。
  • @Value 为基本类型数据注入值

    作用:
     注入基本数据类型和String 类型数据的

     @Value(“tom”)
    private String usename;

示例代码:

@Service("userService")
public class UserServiceImpl implements UserService {
    //创建数据层对象
    @Resource(name="userDaoImpl")  //注解作用是将容器中的name为userDao对象注入到属性userDao
    // @Autowired(required = false)
    // @Qualifier("userDaoImpl3")
    private UserDao userDao;  //如果为false,注入时未能找到,则为null


    public void addUser() {
        userDao.save();
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值