2.3、Bean的管理

一、Bean的装配(IOC应用实现)

        创建应用组件之间的协作的行为通常称为装配(wiring)。Spring IOC通过应用上下文(ApplicationContext)装载Bean的定义并把他们组装起来。

        Spring应用上下文(ApplicationContext)全权负责对象的创建和组装。

        ApplicationContext是Spring IoC容器实现的代表,它负责实例化,配置和组装Bean。容器通过读取配置元数据获取有关实例化、配置和组装哪些对象的说明 。配置元数据可以使用XML、Java注解或Java代码来呈现。它允许你处理应用程序的对象与其他对象之间的互相依赖关系。

二、Bean三种装配(实例化)方式

  • 构造方法
  • 静态工厂
  • 实例工厂
// 三种方式 Bean 的实例化,返回的是一个BeanWrapper,半成品
// 实例工厂,静态工厂,构造方法// 1、工厂实例化
//        1.1、实例工厂方式实例化 return
//        1.2、静态工厂方式实例化 return
// 2、有参构造器实例化(有@Autowired或无@Autowired)
// 3、无参构造实例化

三、搭建spring项目-jar包

如果只是使用spring的基本功能,只需要四个jar包

  • spring-beans
  • spring-core
  • spring-context
  • spring-expression(spel表达式)

用maven搭建spring工程,只需要一个context包就够了,maven帮我们做了上述几个jar包的继承

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.6.RELEASE</version>
</dependency>

四、Spring进行Bean的装配代码行为实现:

我们可以通过下面三种代码行为实现

  1. 显示的xml配置文件方式(使用xml配置文件的方式定义Bean)
  2. 隐示的自动化装配机制(使用Spring自动化注解方式定义Bean)
    @Compont(@serivce @controller @repository) @Autowride,Spring 2.5 支持基于注解的元数据配置. SSM框架开发中的使用
  3. 显示的java注解方式(使用Java注解方式定义Bean)

从 Spring 3.0开始, 由Spring JavaConfig项目提供的功能已经成为Spring核心框架的一部分。因此,你可以使用Java配置来代替XML配置定义外部bean

从spring4.0开始支持springboot1.0之后 springboot完全采用javaConfig的方式进行开发。

1、代码实现一:显示的xml配置文件方式(XML)

原理:xml+dom4j+反射

(1)、创建spring配置文件

一般建议把文件放到src下面,名称随便写建议 applicationContext.xml。如果是maven工程放在resource下面

<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>

(2)、接下来是三种bean装配方式

A:无参构造(常用)

        解析spring配置文件得到对象,这个过程不需要写代码实现,在spring封装对象进行这些操作,这个由ApplicationContext实现

<!-- xml文件配置user对象创建,无参数构造 -->
<bean id="user" class="cn.noargstructure.User" name="设置别名,别名2,使用逗号风的多个别名" scope="singleton" ><description>用来描述一个Bean是干的</description>
</bean>
<!--为外部定义的bean起别名 -->
<alias name="user" alias="user6"></alias>
//测试得到配置的user对象
public static void main(String[] args) {//1 加载spring配置文件,把文件对象创建ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//可以加载多个xml//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");//2 根据配置文件的id值得到对象User user = (User) context.getBean("user");System.out.println(user);
}

B:静态工厂(工厂方法设计模式)

<!-- xml配置,使用静态工厂创建对象 -->
<!-- factory-method指定了工厂类的哪个方法创建Bean-->
<bean id="staticFactory" class="cn.staticfactory.StaticFactory" factory-method="getBean1"/>
// Bean类
public class Bean1 {}//工厂类:
public class Bean1Factory {//静态方法直接创建对象public static Bean1 getBean1() {return new Bean1();}
}
@Test
public void testStaticFactory(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("static-factory.xml");// Bean1 bean = (Bean1) context.getBean("bean1");// 报错, Map<String, BeanDefinition> beanDefinitionMap 没有这bean1的// 有一个叫 staticFactory// StaticFactory staticFactory = (StaticFactory) context.getBean(StaticFactory.class);// 报错, 没有实例化staticFactory这个BeanBean1 bean1 = context.getBean(Bean1.class);Bean1 bean2 = (Bean1) context.getBean("staticFactory");System.out.println(bean1);System.out.println(bean2);// 一级singletonObjects 里面存的name是staticFactory ,对象是 Bean1
}

C:实例工厂

<!-- xml配置工厂Bean,这个工厂Bean是无参构造的方式由Spring创建 -->
<bean id="instanceFactory" class="cn.instancefactory.InstanceFactory"/><!-- 使用工厂对象创建bean2对象 -->
<!-- factory-bean指定实例工厂类 -->
<!-- factory-method指定使用实例工厂的哪个方法创建Bean2 -->
<bean id="bean2" factory-bean="instanceFactory" factory-method="getBean2"/>
public class Bean2 {} // 实例工厂
public class InstanceFactory {public Bean2 getBean2() {return new Bean2();}
}
//实例工厂
@Test
public void testInstanceFactory(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("instance-factory.xml");// 实例工厂先初始化,然后执行实例工厂的FactoryMethod方式实例化Bean2Bean2 bean2 = (Bean2) context.getBean("bean2");System.out.println(bean2);InstanceFactory instanceFactory = (InstanceFactory) context.getBean("instanceFactory");// 一级singletonObjects 里面存的name是 instanceFactory ,对象是 InstanceFactory// 一级singletonObjects 里面存的name是 bean2 ,对象是 Bean2
}

D:有参构造 -- 这里只讲用注解,不用xml

会触发参数的getBean()操作

有@Autowired

@Service
public class People1 {@Autowired(required = false)public People1(People2 people2, People3 people3) {}@Autowired(required = false)public People1(People2 people2) {}
}

无@Autowired

@Service
public class Person1 {public Person1(Person2 person2, Person3 person3) {System.out.println("person 有2参数");}
}

注意

1、有@Autowire的有参构造函数

        1.1、 可以没有无参构造方法

        1.2、required= true,只能有一个有参数构造

        1.3、required= false,可以有多个有参数构造,按顺序取了第一个

2、无@Autowire的有参构造函数

        1.1、有参数构造函数只有一个没问题

        1.2、如果有多个有参数构造函数,必须加无参构造,等于还是无参初始化

        3、1和2混合,2直接被忽略类

2、代码实现二:隐示的自动化装配机制(注解+xml)

使用Spring的注解扫描机制来实现自动化装配,底层是使用spring的aop实现的

注意:使用需要添加spring-aop.jar包,但是maven引入spring-context已经包含了spring-aop。

只演示无参数构造(实际上我们基本上都用无参构造)

1. 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"xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <!-- 方式一:开启注解的扫描,指定扫描路径,到配置的包里面扫描类、方法、属性上面是否有注解--><context:component-scan base-package="cn.ioc.xml.noargstructure"></context:component-scan><!-- 方式二: 这个开启注解扫描,只会扫描属性上面注解--><!-- <context:annotation-config></context:annotation-config> -->
</beans>

2.在Bean类上添加注解@Component

@Component(value="userDao")
public class UserDaoImpl implements UserDao {@Overridepublic void sayHello() {System.out.println("Hello Spring Annotation...");}
}

3.编写测试类

public class TestIoc {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-anno.xml");//getBean 取的是实现类,不是接口。实现类默认Bean ID是类名第一个字母小写,或者有value配置UserDao userDao = (UserDao) context.getBean("userDao");userDao.sayHello();}
}

除了@Component外,Spring提供了3个基本功能和@Component等效的注解,注意不要标记到接口上,标记在类上

  • @Controller 用于对Controller实现类进行标注
  • @Service 用于对Service实现类进行标注
  • @Repository 用于对DAO实现类进行标注
  • @Component

添加value是给bean赋值一个唯一Bean Id,和xml配置装配bean的id一样。可以省略,默认名字是类名第一个字母小写。

上面的xml的bean配置和注解@Component还可以混合使用,底层都是IOC

3、代码实现三:显示的JavaConfig注解方式(基于java的容器配置)(JavaConfig+Spring注解(spring boot))

知识点链接:

基本概念: @Bean 和 @Configuration

  •  @Configuration 注解

绑定Java与XML配置

使用@Configuration+@ComponentScan实现无xml方式的装配,即@Configuration标注的配置类取代了XML配置文件

  • @Configuration相当于之前的applicationComtext.xml配置文件的<beans></beans>
  • @ComponentScan相当于当于<context:component-scan base-package="cn.service"></context:component-scan>开启注解扫描,默认扫描配置文件所在的包及其子包
//配置类
@Configuration // 就相当于创建了一个xml 文件 <beans></beans>
//@ComponentScan("cn.service") //指定路径 //<context:component-scan base-package="cn.service" >
@ComponentScan //默认扫描当前包所在的路径
public class SpringConfig {}

 然后使用@Service @Component @Controller @Repository装Bean

public interface UserService {void method();
}@Service
public class UserServiceImpl implements UserService {@Overridepublic void method() {System.out.println("configuration create UserServiceImpl");}
}
//spring集成测试使用 @RunWith @ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {IocConfig.class})//加载配置类
public class Test1_Ioc {// 注入 ApplicationContext对象,或者直接注入UserService对象@AutowiredApplicationContext applicationContext;@Testpublic void test() {UserService bean = applicationContext.getBean(UserService.class);bean.method();}
}

五、Spring创建第三方bean对象---@Bean

1、注解方式:

  •  @Bean 注解

@Bean是一个方法级别的注解,它与XML中的 元素类似。

注解支持 提供的一些属性,例如 * init-method * destroy-method * autowiring * name

开发者可以在@Configuration类或@Component类中使用@Bean注解。

底层:@Bean是通过实例工厂的方式实现的

BeanDefinition

// beanName就是方法的名字

// BeanDefinition没有class

// BeanDefinition FactoryBeanName 是配置类的名字

// BeanDefinition FactoryMethodName 是配置类的@Bean方法的名字

@Bean的使用

对于第三方的组件类,我们就不能使用自动化装配方案,我们可以使用xml或javaConfig,推荐使用JavaConfig

@Bean可理解为xml里面的标签,如下在配置类添加@Bean注解配置就是装配成功了,此对象就交给spring管理了

/***  可以将一个类的实例(可以干预Bean实例化过程),注册为一个Bean*  会自动将返回值作为Bean的类型    将方法名作为bean的名字*  @Bean(name = "dd") 设置bean的名字及别名(替换)*  @Bean(initMethod = "",destroyMethod = "") =  <bean class="xx" id="xx" init-method="initByConfig" destroy-method="destroyByConfig"></bean>*/
@Configuration
@ComponentScan
public class BeanConfig {@Beanpublic Apple apple(){return new Apple();}
public class Apple {public void say() {System.out.println("我是一个苹果");}
}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {BeanConfig.class})
public class Test2_Bean {@Autowiredprivate Apple apple;@Testpublic void test01() {apple.say();}
} 
  • 怎么去自动依赖外部Bean:直接在方法里面写上需要依赖的参数即可,不需要写@Autowired
  • 怎么去自动依赖配置类内部Bean:直接调用方法即可
    • 注入内部bean依赖
@Configuration
@ComponentScan
public class BeanConfig {@Beanpublic Person person(){System.out.println(man().hi());return new Person("张三");}@Beanpublic Man man(){return new Man();}
}public class Man {public String hi(){return "你好";}
}public class Person {private String name;public String getName() {return name;}public Person(String name) {this.name = name;}public void sayHello(String hi) {System.out.println(hi + " ,我是" + getName() );}
}

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {BeanConfig.class})
public class Test2_Bean {@Autowiredprivate Person person;@Testpublic void test02(){person.sayHello("你好");}
}
  • Bean之间的依赖 -注入外部Bean - @Import

我们可以使用方法参数来实现该依赖关系,如以下示例所示:

@Configuration
@ComponentScan // 开启注解扫描,要扫@Service标注的Banana
@Import(BeanConfig.class) //引入BeanConfig配置类,Apple在BeanConfig配置
public class Bean2Config {@Beanpublic Monkey monkey(Banana banana, Apple apple) {return new Monkey(banana.banana(),apple.apple());}
}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {Bean2Config.class})
public class Test2_Bean {@Autowiredprivate Monkey monkey;@Testpublic void test03(){monkey.eat();}
}
  • 接收生命周期回调 initMetohd和destroyMethod

相当于在xml的配置的init-method和destrouy-method

//init-method="initByConfig" destroy-method="destroyByConfig"
@Bean(initMethod = "initByConfig",destroyMethod = "destroyByConfig")
public PayService getPayService(){return new PayServiceImpl();
}public class PayServiceImpl implements PayService {@Overridepublic void print() {System.out.println("@Bean create PayServiceImpl");}@Overridepublic void initByConfig() {System.out.println("PayService-初始化");}@Overridepublic void destroyByConfig() {System.out.println("PayService-销毁");}
  • 指定 Bean 的作用域 @Scope
    @Configuration
    public class MyConfiguration {@Bean@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)public Encryptor encryptor() {// ...}
    }
  • 自定义Bean的名字
//默认情况下,配置类使用@Bean方法的名称作为结果bean的名称。 
//但是,可以使用name属性覆盖此功能,如以下示例所示:
@Configuration
public class AppConfig {@Bean(name = "myThing")//多个别名:@Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })public Thing thing() {return new Thing();}
}

2、xml方式

在Spring中,很多对象都是单实例的,在日常的开发中,我们经常需要使用某些外部的单实例对象,例如数据库连接池,下面我们来讲解下如何在spring中创建第三方bean实例。

1、导入数据库连接池的pom文件

<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
</dependency>

2、编写配置文件

ioc.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="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="username" value="root"></property><property name="password" value="123456"></property><property name="url" value="jdbc:mysql://localhost:3306/demo"></property><property name="driverClassName" value="com.mysql.jdbc.Driver"></property></bean>
</beans>

3、编写测试文件

​public class MyTest {public static void main(String[] args) throws SQLException {ApplicationContext context = new ClassPathXmlApplicationContext("ioc3.xml");DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);System.out.println(dataSource);System.out.println(dataSource.getConnection());}
}

3、FactoryBean

public class Bnana {
}
@Service
public class BananaBean implements FactoryBean {@Overridepublic Banana getObject() {return new Banana();}@Overridepublic Class<?> getObjectType() {return Banana.class;}
}
@Service
public class Fruit {@Autowiredprivate Bnana Bnana;
}

4、导入ImportSelector实现类,可以注册多个bean @Import({MyImportSelector.class})

六、Spring Bean 管理的方式注解和xml的比较

七、jdk9以上就废弃了@PostConstruct,如果想继续使用@PostConstruct有两种方法:

1、引入java注解包,

2、现Spring 提供的  InitializingBean和 DisposableBean接口的效果和使用@PostConstruct和@PreDestroy 注解的效果一样。(推荐)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/2252.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows服务器自带IIS搭建网站并发布公网访问【内网穿透】

文章目录 1.前言2.Windows网页设置2.1 Windows IIS功能设置2.2 IIS网页访问测试 3. Cpolar内网穿透3.1 下载安装Cpolar3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5.结语 转载自远程源码文章&#xff1a;【IIS搭建网站】本地电脑做服务器搭建web站点并公网访问「内网…

面试常问 什么是回表?为什么需要回表?

小伙伴们在面试的时候&#xff0c;有一个特别常见的问题&#xff0c;那就是数据库的回表。什么是回表&#xff1f;为什么需要回表&#xff1f; 索引结构 要搞明白这个问题&#xff0c;需要大家首先明白 MySQL 中索引存储的数据结构。这个其实很多小伙伴可能也都听说过&#xf…

iOS多语言解决方案全面指南

本文以及相关工具和代码旨在为已上线的iOS项目提供一种快速支持多语言的解决方案。由于文案显示是通过hook实现的&#xff0c;因此对App的性能有一定影响&#xff1b;除了特殊场景的文案显示需要手动支持外&#xff0c;其他任务均已实现自动化。 本文中的部分脚本代码基于 Chat…

第三方医药数据供应商有哪些?--数据业务介绍

第三方医药数据供应商主要是为医药企业、健康机构、学术研究、药物研发等提供医药相关数据的收集、整理、分析和应用服务。随着医药市场的需求衍生了许多各高垂直领域的医药数据供应商&#xff0c;这也导致了大家对医药数据供应商涉及领域认识的片面性。 故本文重点介绍各医药…

用API Key保护Spring Boot 接口的安全

1、概述 安全性在REST API开发中扮演着重要的角色。一个不安全的REST API可以直接访问到后台系统中的敏感数据。因此&#xff0c;企业组织需要关注API安全性。 Spring Security 提供了各种机制来保护我们的 REST API。其中之一是 API 密钥。API 密钥是客户端在调用 API 调用时提…

HDFS之Java客户端操作

HDFS之Java客户端操作 文章目录 HDFS之Java客户端操作写在前面准备Windows关于Hadoop的开发环境下载依赖配置HADOOP_HOME环境变量配置Path环境变量 创建Maven工程XML文件创建新的Package创建HdfsClient类执行程序 HDFS的API操作 写在前面 Hadoop版本&#xff1a;Hadoop-3.1.3L…

Redis实战——短信登录(二)

Redis代替session redis中设计key 在使用session时&#xff0c;每个用户都会有自己的session&#xff0c;这样虽然验证码的键都是“code”&#xff0c;但是相互不影响&#xff0c;从而确保每个用户获取到的验证码只能够自己使用&#xff0c;当使用redis时&#xff0c;redis的ke…

【永久服务器】EUserv

1. 请先自行准备网络&#xff08;我用的伦敦还可以&#xff09;、以及visa卡&#xff0c;淘宝可以代付&#xff0c;我总共花了97人民币&#xff08;10.94欧代付费&#xff09; 现在只能申请一台&#xff0c;多了会被删除&#xff0c;也就是两欧元&#xff0c;然后选择visa卡 选…

Appium之xpath定位详解

目录 一、基础定位 二、contains模糊定位 三、组合定位 四、层级定位 前面也说过appium也是以webdriver为基的&#xff0c;对于元素的定位也基本一致&#xff0c;只是增加一些更适合移动平台的独特方式&#xff0c;下面将着重介绍xpath方法&#xff0c;这应该是UI层元素定位…

linux查找文件内容命令之grep -r ‘关键字‘

目录 grep命令介绍参数选项 grep命令的使用1. 在指定的文件中查找包含的关键字2. 在指定目录下多个文件内容中查找包含的关键字3.在追加的文件内容中查找关键字4. 统计文件中关键字出现的次数5. vi或vim打开的文件查找关键字(补充) 总结 grep命令介绍 Linux操作系统中 grep 命…

C++面向对象丨4. 文件操作

操作系统&#xff1a;Windows IDE&#xff1a;Visual Studio 2019 文章目录 1 文本文件1.1 写文件1.2 写文件实例1.3 读文件1.4 读文件实例 2 二进制文件2.1 写文件2.2 写文件实例2.2 读文件2.4 读文件实例 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行结束都会…

【虚拟机搭建-VMware设置固定IP】VMWare中CentOS如何设置固定IP【不成功手把手教学】

1、背景 在日常工作学习中&#xff08;比如博主在之前学习k8s过程中&#xff0c;windows本地搭建虚拟机&#xff0c;重启windows后&#xff09;虚拟机的IP会发生变化&#xff0c;所以该篇文章详细记录VMWare中CentOS如何设置固定IP 2、虚拟机安装 参考&#xff1a; https:/…