栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring:二、Bean管理-XML方式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring:二、Bean管理-XML方式

Spring:二、Bean管理-XML方式

1 IOC

1 IoC思想基于IoC容器完成,IoC容器底层就是对象工厂。

2 spring提供IoC容器实现两种方式:(两个接口)

(1)BeanFactory:IoC容器基本实现,是spring内部的使用接口,不提供开发人员进行使用(加载配置文件时不会创建对象,在获取对象(使用)时才去创建对象)

(2)ApplicationContext:BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员进行使用(加载配置文件时候就会把配置文件对象进行创建)

idea上点击ApplicationContext,按下ctrl+h:


小区别:ClassPathXmlApplicationContext在文件相应的路径下即可,不需要全部路径名;FileSystemXmlApplicationContext需要文件的全部路径

2 XML使用

2.1 默认使用无参构造方法

修改User类,使其只含有含参构造方法:

package com.xiaoxu.pojo;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class User {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "User{" +
                "str='" + str + ''' +
                '}';
    }
}

新建测试类Myuser:

import com.xiaoxu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Myuser {
    public static void main(String[] args) {
        ApplicationContext a=new ClassPathXmlApplicationContext("xiaoxu.xml");
        System.out.println(a);
        User u= (User)a.getBean("hello_spring");
        System.out.println(u);
    }
}

xiaoxu.xml:




    
    
        
    

执行报错:

上述代码,去掉User类的@AllArgsConstructor注解即可。当< bean >标签中没有任何构造方法相关的标签时(constructor-arg)默认是使用无参构造方法。

2.2 基于xml方式注入属性

(1)DI(Dependency Injection)依赖注入,即注入属性

第一种方式:使用set方法进行注入

1 类中添加属性和相应的set方法(使用property标签注入属性,如果实体类不存在该property的set方法,会抛错)

2 bean中添加property(property标签里需要添加name和value属性,name代表需要set的变量名称,value是赋值,多个变量赋值,多个property标签即可):

第二种方式:使用有参构造方法注入属性

lombok只添加@AllArgsConstructor装饰器时,只会含有有参构造方法,没有无参构造方法。

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private String str;
    private int age;
}

xiaoxu.xml:




    
    
        
        
    

import com.xiaoxu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Myuser {
    public static void main(String[] args) {
        ApplicationContext a=new ClassPathXmlApplicationContext("xiaoxu.xml");
        User u=a.getBean("youcanUser",User.class);
        System.out.println(u);
    }
}
User(str=xiaoxu, age=26)

2.3 p命名空间

使用p名称标签,xml中提示URL找不到:

在idea的File -> settings中:


然后观察xml(可以识别了):

修改xiaoxu.xml如下,增加:xmlns:p=“http://www.springframework.org/schema/p”:



        





    
    

因为是无参构造的bean,所以在User类中增加无参构造方法即可:

package com.xiaoxu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String str;
    private int age;
}

调用:

import com.xiaoxu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Myuser {
    public static void main(String[] args) {
        ApplicationContext a=new ClassPathXmlApplicationContext("xiaoxu.xml");
        User u=a.getBean("youcanUser",User.class);
        System.out.println(u);
    }
}
User(str=小徐呀, age=28)

2.4 注入空值和特殊符号

2.4.1 注入空值null

User.java:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String str;
    private int age;
    private String address;
}

xiaoxu.xml:




    
        
    

Myuser.java:

import com.xiaoxu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Myuser {
    public static void main(String[] args) {
        ApplicationContext a=new ClassPathXmlApplicationContext("xiaoxu.xml");
        User u=a.getBean("youcanUser",User.class);
        System.out.println(u);
    }
}

2.4.2 注入特殊符号

修改上述xiaoxu.xml即可:




    
    
        
            ]]>
        
    

重新执行:

User(str=小徐呀, age=28, address=<重庆>)

2.5 注入属性-外部bean

UserDao:

package com.xiaoxu.dao;

public interface UserDao {
    void getUser();
}

UserDaoImpl:

package com.xiaoxu.dao;

public class UserDaoImpl implements UserDao{
    public void getUser(){
        System.out.println("获取用户的数据");
    }
}

UserDaoMysqlImpl:

package com.xiaoxu.dao;

public class UserDaoMysqlImpl implements UserDao{
    @Override
    public void getUser(){
        System.out.println("Mysql获取用户数据!");
    }
}

UserService:

package com.xiaoxu.service;

public interface UserService {
    void getUser();
}

UserServiceImpl:

package com.xiaoxu.service;

import com.xiaoxu.dao.UserDao;

public class UserServiceImpl implements UserService{
    //服务层调用dao层
    private UserDao userDao;

    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUser(){
        userDao.getUser();
    }
}

myUser.xml:




    
    
    

    
        
    

2.6 注入属性-级联赋值

(1)一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门,部门是一,员工是多
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

Dept类:

package com.xiaoxu.bean;

//部门类
public class Dept {
    private String dept;

    public void setDept(String dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dept='" + dept + ''' +
                '}';
    }
}

Emp类:

package com.xiaoxu.bean;

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某个部门,使用对象形式表示
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "ename='" + ename + ''' +
                ", gender='" + gender + ''' +
                ", dept=" + dept +
                '}';
    }
}

(3)在spring配置文件中进行配置

配置前,先在idea配置一下xml的初始化模板:









beans1.xml:



    
        
        
        
        
    
    
        
    

TestDept.java:

import com.xiaoxu.bean.Emp;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class TestDept {
    @Test
    public void testDep(){
        ApplicationContext context= new ClassPathXmlApplicationContext("beans1.xml");
        Emp e=context.getBean("emp", Emp.class);
        System.out.println(e);

    }
}
Emp{ename='xiaoxu', gender='man', dept=Dept{dept='会计部'}}

还可以换种写法:
Emp:

Dept:

public class TestDept {
    @Test
    public void testDep(){
        ApplicationContext context= new ClassPathXmlApplicationContext("beans1.xml");
        Emp e=context.getBean("emp", Emp.class);
        System.out.println(e);
    }
}

执行结果如下:

Emp{ename='xiaoxu', gender='man', dept=Dept{dname='技术部'}}

2.7 注入集合类型属性

2.7.1

若需要传递类似于 Java Collection 类型的值,例如 List、Set、Map 和 properties,可以使用 Spring 提供的集合配置标签:

标签说明
< list >用于注入 list 类型的值,允许重复
< set >用于注入 set 类型的值,不允许重复
< map >用于注入 key-value 的集合,其中 key-value 可以是任意类型
< props >用于注入 key-value 的集合,其中 key-value 都是字符串类型

新建学生类,含有集合类型属性:

package com.xiaoxu.collectionType;

import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

@Data
public class Stu {
    //1.数组类型属性
    private String[] courses;
    //2.list集合类型属性
    private List l;
    //3.map集合类型属性
    private Map m;
    //4.set集合类型属性
    private Set s;
    //5.properties
    private Properties p;
}


beans1.xml:




        
            
            
                
                    java课程
                    python课程
                
            
            
            
            
                
                    小徐
                    小李
                
            

            
            
                
                    
                    
                
            

            
            
                
                    Spring
                    Django
                
            
            
            
            
                
                    xyz
                    abc
                
            
        

测试类:

import com.xiaoxu.collectionType.Stu;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class TestStu {
    @Test
    public void test_01(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans1.xml");
        Stu student=context.getBean("stu",Stu.class);
        System.out.println(Arrays.toString(student.getCourses()));
        System.out.println(student.getL());
        System.out.println(student.getM());
        System.out.println(student.getS());
        System.out.println(student.getP());
    }
}

执行结果:

[java课程, python课程]
[小徐, 小李]
{JAVA=java, PYTHON=python}
[Spring, Django]
{two=abc, one=xyz}

2.7.2 注入list集合类型,值是对象

新建课程类:

Courses (@Data会带上getter、setter、toString):

package com.xiaoxu.collectionType;

import lombok.Data;

//课程类
@Data
public class Courses {
    private String cname; //课程名称
}

修改beans1.xml:




        
            
            
                
                    java课程
                    python课程
                
            

            
            
                
                    小徐
                    小李
                
            

            
            
                
                    
                    
                
            

            
            
                
                    Spring
                    Django
                
            

            
            
                
                    xyz
                    abc
                
            

            
            
                
                    
                    
                
            
        
        
        
            
        
        
            
        

执行测试类:

@Test
public void test_01(){
    ApplicationContext context=new ClassPathXmlApplicationContext("beans1.xml");
    Stu student=context.getBean("stu",Stu.class);
    System.out.println(Arrays.toString(student.getCourses()));
    System.out.println(student.getL());
    System.out.println(student.getM());
    System.out.println(student.getS());
    System.out.println(student.getP());
    System.out.println(student.getCoursesList());
}
[java课程, python课程]
[小徐, 小李]
{JAVA=java, PYTHON=python}
[Spring, Django]
{two=abc, one=xyz}
[Courses(cname=Spring5框架), Courses(cname=SpringBoot框架)]

2.7.3 把集合注入部分提取出来

新建Book类:

package com.xiaoxu.collectionType;

import lombok.Data;

import java.util.List;

@Data
public class Book {
    private List book_list;
}

(1)在spring配置文件中引入名称空间(util)






beans2.xml:




        
        
            java从入门到放弃
            python从入门到成功
        
        
        
            
        

测试方法:

@Test
public void test_02(){
    ApplicationContext context=new ClassPathXmlApplicationContext("beans2.xml");
    Book b=context.getBean("book",Book.class);
    System.out.println(b.getBook_list());
}
[java从入门到放弃, python从入门到成功]

2.8 工厂bean

spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)

(1)普通bean:在配置文件中定义bean类型就是返回类型
(2)工厂bean:在配置文件定义bean类型可以和返回类型不一样:一、创建类,让这个类作为工厂bean,实现接口FactoryBean;二、实现接口里面的方法,在实现的方法中定义返回的bean类型

MyBean:

package com.xiaoxu.factorybean;

import com.xiaoxu.collectionType.Courses;
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean {
    //定义返回bean
    @Override
    public Courses getObject() throws Exception {
        Courses c=new Courses();
        c.setCname("java入门");
        return c;
    }

    @Override
    public Class getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

MyBean.xml:




        

        


测试类:

import com.xiaoxu.collectionType.Courses;
import com.xiaoxu.factorybean.MyBean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestMyBean {
    @Test
    public void test_01(){
        ApplicationContext context=new ClassPathXmlApplicationContext("MyBean.xml");
        Courses my=context.getBean("mybean", Courses.class);
        System.out.println(my);
    }
}
Courses(cname=java入门)

2. 9 xml中bean默认是单例对象(Bean的作用域)

单个bean标签创建的对象,是同一个内存地址:

import com.xiaoxu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Myuser {
    public static void main(String[] args) {
        ApplicationContext a=new ClassPathXmlApplicationContext("xiaoxu.xml");
        System.out.println(a);
        User u= (User)a.getBean("hello_spring");
        System.out.println(u);
        User u1=a.getBean("hello_spring",User.class);
        System.out.println(u1);
        System.out.println(u==u1);
    }
}
org.springframework.context.support.ClassPathXmlApplicationContext@b1bc7ed, started on Wed Nov 10 14:01:41 CST 2021
User{str='hello my spring!'}
User{str='hello my spring!'}
true

bean的作用域可以通过scope属性进行控制:

Spring 5 支持以下 6 种作用域。
1)singleton
默认值,单例模式,表示在 Spring 容器中只有一个 Bean 实例,Bean 以单例的方式存在。
2)prototype
原型模式,表示每次通过 Spring 容器获取 Bean 时,容器都会创建一个 Bean 实例。
3)request
每次 HTTP 请求,容器都会创建一个 Bean 实例。该作用域只在当前 HTTP Request 内有效。
4)session
同一个 HTTP Session 共享一个 Bean 实例,不同的 Session 使用不同的 Bean 实例。该作用域仅在当前 HTTP Session 内有效。
5)application
同一个 Web 应用共享一个 Bean 实例,该作用域在当前 ServletContext 内有效。

类似于 singleton,不同的是,singleton 表示每个 IoC 容器中仅有一个 Bean 实例,而同一个 Web 应用中可能会有多个 IoC 容器,但一个 Web 应用只会有一个 ServletContext,也可以说 application 才是 Web 应用中货真价实的单例模式。
6)websocket
websocket 的作用域是 WebSocket ,即在整个 WebSocket 中有效。

request、session、application、websocket 和 global Session 作用域只能在 Web 环境下使用,如果使用 ClassPathXmlApplicationContext 加载这些作用域中的任意一个的 Bean,就会抛出以下异常。

java.lang.IllegalStateException: No Scope registered for scope name 'xxx'

singleton
singleton 是 Spring 容器默认的作用域。当 Bean 的作用域为 singleton 时,Spring 容器中只会存在一个共享的 Bean 实例。该 Bean 实例将存储在高速缓存中,并且所有对 Bean 的请求,只要 id 与该 Bean 定义相匹配,都会返回该缓存对象。

通常情况下,这种单例模式对于无会话状态的 Bean(如 DAO 层、Service 层)来说,是最理想的选择。

prototype
对于 prototype 作用域的 Bean,Spring 容器会在每次请求该 Bean 时都创建一个新的 Bean 实例。prototype 作用域适用于需要保持会话状态的 Bean(如 Struts2 的 Action 类)。

修改beans2.xml,scope=“prototype”:




        
        
            java从入门到放弃
            python从入门到成功
        
        
        
            
        

@Test
public void test_02(){
    ApplicationContext context=new ClassPathXmlApplicationContext("beans2.xml");
    Book b=context.getBean("book",Book.class);
    Book b2=context.getBean("book",Book.class);
    System.out.println(b==b2);
}
false

说明scope="prototype"时,多次创建的对象内存地址不是同一个了。

(1)singleton是单实例,加载spring配置文件时就会创建单实例对象
(2)prototype是多实例,不是在加载spring配置文件时候创建对象,在调用getBean方法时创建多实例对象(懒加载)

2.10 Bean的生命周期

在传统的 Java 应用中,Bean 的生命周期很简单,使用关键字 new 实例化 Bean,当不需要该 Bean 时,由 Java 自动进行垃圾回收。

Spring 中 Bean 的生命周期较复杂,可以表示为:Bean 的定义 -> Bean 的初始化 -> Bean 的使用 -> Bean 的销毁。

Spring 根据 Bean 的作用域来选择管理方式。对于 singleton 作用域的 Bean,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成,以及何时被销毁;而对于 prototype 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给客户端代码管理,Spring 容器将不再跟踪其生命周期。

(1)生命周期:从对象创建到对象销毁的过程
(2)bean生命周期:1、通过构造器创建bean实例(无参数构造)2、为bean的属性设置值和对其他bean引用(调用set方法)3、调用bean的初始化方法(需要进行配置初始化的方法) 4、bean可以使用(获取到了对象)5、当容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法)

ordes:

package com.xiaoxu.bean;

public class ordes {
    public ordes(){
        System.out.println("第一步执行了order无参构造创建bean实例...");
    }
    private String oname;

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步执行了set方法");
    }

    //创建执行的初始化方法,需要去xml中配置
    public void initMethod_xiaoxu(){
        System.out.println("第三步执行了初始化方法");
    }

    //创建执行的销毁的方法
    public void destroyMethod(){
        System.out.println("第五步手动来销毁..");
    }
}

beans3.xml:




        
            
        

测试类:

import com.xiaoxu.bean.ordes;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test_01(){
//        ApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans3.xml");
        ordes  o = context.getBean("order",ordes.class);
        System.out.println("第四步获取创建bean实例");
        System.out.println(o);

        //手动让bean实例销毁
        context.close();
    }
}
第一步执行了order无参构造创建bean实例...
第二步执行了set方法
第三步执行了初始化方法
第四步获取创建bean实例
com.xiaoxu.bean.ordes@706a04ae
第五步手动来销毁..

加上bean的后置处理器,在第三部之前和之后添加,bean的生命周期有7步:
(3)之前:把bean实例传递bean后置处理器的方法 (3)之后:把bean实例传递bean后置处理器的方法


MyBeanPost:

package com.xiaoxu.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法");
        return bean;
    }
}

beans3.xml:




        
            
        

        
        

执行测试类:

第一步执行了order无参构造创建bean实例...
第二步执行了set方法
在初始化之前执行的方法
第三步执行了初始化方法
在初始化之后执行的方法
第四步获取创建bean实例
com.xiaoxu.bean.ordes@47db50c5
第五步手动来销毁..

2.11 xml自动装配

Emp:

package com.xiaoxu.pojo;

import lombok.Data;

@Data
public class Emp {
    private Dept de;
}

Dept:

package com.xiaoxu.pojo;

import lombok.Data;

@Data
public class Dept {
    private String dname;
}

beans4.xml:



        
        

        
        
            
        

测试类:

import com.xiaoxu.pojo.Emp;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest2 {
    @Test
    public void test_01(){
        ApplicationContext context=new ClassPathXmlApplicationContext("beans4.xml");
        Emp e=context.getBean("emp", Emp.class);
        System.out.println(e);
    }
}
Emp(de=Dept(dname=技术部))

根据类型自动注入:

修改xml重新执行:



        
        

        
        
            
        

Emp(de=Dept(dname=技术部))

注意,byType,相同类型的bean不能定义多个。

2.12 IoC操作Bean管理(外部属性文件)

(1)直接配置数据库信息:配置德鲁伊连接池
(2)引入德鲁伊连接池依赖jar包

查询maven依赖:https://search.maven.org/


  com.alibaba
  druid
  1.2.8

beans.xml:
url的value,端口号后面是数据库名称;
username和password是数据库的账户和密码。



        
        
            
            
            
            
        

(2)引入外部属性文件配置数据库连接池

1 新建xx_jdbc.properties文件

同样在resource目录下,新建xx_jdbc.properties文件:

注意:左边前缀需要加上,否则可能会造成字段的冲突。

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/mybook
prop.userName=root
prop.password=

2 把外部properties属性文件引入到spring配置文件中:引入context名称空间



        
        






        
        
        
        
        
        
            
            
            
            
        

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/571871.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号