spring(1)https://developer.aliyun.com/article/1530428
2.2.9、实验九:p命名空间
引入p命名空间后,可以通过以下方式为bean的各个属性赋值
<bean id="studentSix" class="com.atguigu.spring.pojo.Student" p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>
2.2.10、实验十:引入外部属性文件
①加入依赖
<!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!-- 数据源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.31</version> </dependency>
②创建外部属性文件
jdbc.user=root jdbc.password=atguigu jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC jdbc.driver=com.mysql.cj.jdbc.Driver
③引入属性文件
[!note]
<!-- 引入外部属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/>
④配置bean
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${jdbc.url}"/> <property name="driverClassName" value="${jdbc.driver}"/> <property name="username" value="${jdbc.user}"/> <property name="password" value="${jdbc.password}"/> </bean>
⑤测试
@Test public void testDataSource() throws SQLException { ApplicationContext ac = new ClassPathXmlApplicationContext("spring-datasource.xml"); DataSource dataSource = ac.getBean(DataSource.class); Connection connection = dataSource.getConnection(); System.out.println(connection); }
2.2.11、实验十一:bean的作用域
①概念
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表:
[!note]
scope:设置bean的作用域
scope=“singleton / prototype”
singleton(单例):表示获取该bean所对应的对象都是同一个
protcype(多例):表示获取该bean所对应的对象都不是同一个
取值 | 含义 | 创建对象的时机 |
singleton(默认) | 在IOC容器中,这个bean的对象始终为单实例 | IOC容器初始化时 |
prototype | 这个bean在IOC容器中有多个实例 | 获取bean时 |
单例的情况有可能会出问题 | ||
- action是被ioc管理了,所以数据都是同一个
但是通过网页上传的修改对象的功能已经修改的bean中的user类对象,user类对象中已经有id了,所以他使用的就是上一次的id,然后把后面添加的数据覆盖了第一次修改的数据
如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用):
取值 | 含义 |
request | 在一个请求范围内有效 |
session | 在一个会话范围内有效 |
2.2.12、实验十二:bean的生命周期
①具体的生命周期过程
- bean对象创建(调用无参构造器)
- 给bean对象设置属性
- bean对象初始化之前操作(由bean的后置处理器负责)
- bean对象初始化(需在配置bean时指定初始化方法)
- bean对象初始化之后操作(由bean的后置处理器负责)
- bean对象就绪可以使用
- bean对象销毁(需在配置bean时指定销毁方法)
- IOC容器关闭
②修改类User
public class User { private Integer id; private String username; private String password; private Integer age; public User() { System.out.println("生命周期:1、创建对象"); } public User(Integer id, String username, String password, Integer age) { this.id = id; this.username = username; this.password = password; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { System.out.println("生命周期:2、依赖注入"); this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public void initMethod(){ System.out.println("生命周期:3、初始化"); } public void destroyMethod(){ System.out.println("生命周期:5、销毁"); } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + '}'; } }
注意其中的initMethod()和destroyMethod(),可以通过配置bean指定为初始化和销毁的方法
③配置bean
[!note]
使用init-method属性指定初始化方法
使用destroy-method属性指定销毁方法
<!-- 使用init-method属性指定初始化方法 --> <!-- 使用destroy-method属性指定销毁方法 --> <bean class="com.atguigu.bean.User" scope="prototype" init-method="initMethod"destroy-method="destroyMethod"> <property name="id" value="1001"></property> <property name="username" value="admin"></property> <property name="password" value="123456"></property> <property name="age" value="23"></property> </bean>
④测试
[!note]
1,实例化
2、依赖注入
3,初始化
4、IOC容器关时销毁
,
ConfiqurableApplicationContext
是ApplicationContext的子接口,其中扩展了刷新和关闭容器的方法
@Test public void testLife(){ ConfiqurableApplicationContext ac = newClassPathXmlApplicationContext("spring-lifecycle.xml"); User bean = ac.getBean(User.class); System.out.println("生命周期:4、通过IOC容器获取bean并使用"); ac.close(); }
单例的时候在获取容器的时候就把对象给创建好,多例的时候是在获取bean的时候创建
⑤bean的后置处理器
bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,
且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行
创建bean的后置处理器:
package com.atguigu.spring.process; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("☆☆☆" + beanName + " = " + bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("★★★" + beanName + " = " + bean); return bean; } }
在IOC容器中配置后置处理器:
<
bean id="myBeanProcessor"class="com.atguigu.spring.process.MyBeanProcessor"/>
2.2.13、实验十三:FactoryBean
配置到ioc容器,获取的时候可以直接获取这个工厂提供的对象,不用先获取工厂再获取对象
①简介
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个
FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是
getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
当把FactoryBean的实现类醒置为bean时,会将当前类中getobject()所返回的对象交给Ioc容器管理
将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
/* * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory; import org.springframework.lang.Nullable; /** * Interface to be implemented by objects used within a {@link BeanFactory} which * are themselves factories for individual objects. If a bean implements this * interface, it is used as a factory for an object to expose, not directly as a * bean instance that will be exposed itself. * * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b> * A FactoryBean is defined in a bean style, but the object exposed for bean * references ({@link #getObject()}) is always the object that it creates. * * <p>FactoryBeans can support singletons and prototypes, and can either create * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean} * interface allows for exposing more fine-grained behavioral metadata. * * <p>This interface is heavily used within the framework itself, for example for * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for * custom components as well; however, this is only common for infrastructure code. * * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not * supposed to rely on annotation-driven injection or other reflective facilities.</b> * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the * bootstrap process, even ahead of any post-processor setup. If you need access to * other beans, implement {@link BeanFactoryAware} and obtain them programmatically. * * <p><b>The container is only responsible for managing the lifecycle of the FactoryBean * instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore, * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()} * will <i>not</i> be called automatically. Instead, a FactoryBean should implement * {@link DisposableBean} and delegate any such close call to the underlying object. * * <p>Finally, FactoryBean objects participate in the containing BeanFactory's * synchronization of bean creation. There is usually no need for internal * synchronization other than for purposes of lazy initialization within the * FactoryBean itself (or the like). * * @author Rod Johnson * @author Juergen Hoeller * @since 08.03.2003 * @param <T> the bean type * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.aop.framework.ProxyFactoryBean * @see org.springframework.jndi.JndiObjectFactoryBean */ public interface FactoryBean<T> { /** * The name of an attribute that can be * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a * {@link org.springframework.beans.factory.config.BeanDefinition} so that * factory beans can signal their object type when it can't be deduced from * the factory bean class. * @since 5.2 */ String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; /** * Return an instance (possibly shared or independent) of the object * managed by this factory. * <p>As with a {@link BeanFactory}, this allows support for both the * Singleton and Prototype design pattern. * <p>If this FactoryBean is not fully initialized yet at the time of * the call (for example because it is involved in a circular reference), * throw a corresponding {@link FactoryBeanNotInitializedException}. * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null} * objects. The factory will consider this as normal value to be used; it * will not throw a FactoryBeanNotInitializedException in this case anymore. * FactoryBean implementations are encouraged to throw * FactoryBeanNotInitializedException themselves now, as appropriate. * @return an instance of the bean (can be {@code null}) * @throws Exception in case of creation errors * @see FactoryBeanNotInitializedException */ @Nullable T getObject() throws Exception; /** * Return the type of object that this FactoryBean creates, * or {@code null} if not known in advance. * <p>This allows one to check for specific types of beans without * instantiating objects, for example on autowiring. * <p>In the case of implementations that are creating a singleton object, * this method should try to avoid singleton creation as far as possible; * it should rather estimate the type in advance. * For prototypes, returning a meaningful type here is advisable too. * <p>This method can be called <i>before</i> this FactoryBean has * been fully initialized. It must not rely on state created during * initialization; of course, it can still use such state if available. * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return * {@code null} here. Therefore it is highly recommended to implement * this method properly, using the current state of the FactoryBean. * @return the type of object that this FactoryBean creates, * or {@code null} if not known at the time of the call * @see ListableBeanFactory#getBeansOfType */ @Nullable Class<?> getObjectType(); /** * Is the object managed by this factory a singleton? That is, * will {@link #getObject()} always return the same object * (a reference that can be cached)? * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object, * the object returned from {@code getObject()} might get cached * by the owning BeanFactory. Hence, do not return {@code true} * unless the FactoryBean always exposes the same reference. * <p>The singleton status of the FactoryBean itself will generally * be provided by the owning BeanFactory; usually, it has to be * defined as singleton there. * <p><b>NOTE:</b> This method returning {@code false} does not * necessarily indicate that returned objects are independent instances. * An implementation of the extended {@link SmartFactoryBean} interface * may explicitly indicate independent instances through its * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean} * implementations which do not implement this extended interface are * simply assumed to always return independent instances if the * {@code isSingleton()} implementation returns {@code false}. * <p>The default implementation returns {@code true}, since a * {@code FactoryBean} typically manages a singleton instance. * @return whether the exposed object is a singleton * @see #getObject() * @see SmartFactoryBean#isPrototype() */ default boolean isSingleton() { return true; } }
②创建类UserFactoryBean
public class UserFactoryBean implements FactoryBean<User> { @Override public User getObject() throws Exception { return new User(); } @Override public Class<?> getObjectType() { return User.class; } }
③配置bean
<bean id="user" class="com.atguigu.bean.UserFactoryBean"></bean>
④测试
@Test public void testUserFactoryBean(){ //获取IOC容器 ApplicationContext ac = new ClassPathXmlApplicationContext("spring-factorybean.xml"); User user = (User) ac.getBean("user"); System.out.println(user); }
2.2.14、实验十基于xml的自动装配
自动装配:
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
ioc容器中所有类类型的属性,都可以在ioc容器中找到匹配的bean为属性赋值,之前是配置proprieties引用
①场景模拟
创建类UserController
public class UserController { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public void saveUser(){ userService.saveUser(); } }
创建接口UserService
public interface UserService { void saveUser(); }
创建类UserServiceImpl实现接口UserService
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void saveUser() { userDao.saveUser(); } }
创建接口UserDao
public interface UserDao { void saveUser(); }
创建类UserDaoImpl实现接口UserDao
public class UserDaoImpl implements UserDao { @Override public void saveUser() { System.out.println("保存成功"); } }
bean引用
[!danger]
引用的bean的实现类,当使用的实现类发生改变,换个新的实现类引用即可
<?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="userController" class="com.atguigu.spring.controller.UserController"> <property name="userService" ref="userService"></property> </bean> <bean id="userService" class="com.atguigu.spring.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.atguigu.spring.dao.imlp.UserDaoImpl"></bean> </beans>
测试
public class AutoWireTest { @Test public void testAutoWire(){ ApplicationContext ioc= new ClassPathXmlApplicationContext("spring-autowire.xml"); UserController bean = ioc.getBean(UserController.class); bean.saveUser(); } }
②配置bean
使用bean标签的autowire属性设置自动装配效果
自动装配方式:byType
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值
null
若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常
NoUniqueBeanDefinitionException
[!note]
总结:当使用byType实现自动装配时,IoC容器中有且只有一个类型匹配的bean能够为属性赋值,
而且相同类型的bean只需配一次,如果需要多个只需要设置作用域使之成为多例模式即可
<bean id="userController"class="com.atguigu.autowire.xml.controller.UserController" autowire="byType"> </bean> <bean id="userService"class="com.atguigu.autowire.xml.service.impl.UserServiceImpl" autowire="byType"> </bean> <bean id="userDao" class="com.atguigu.autowire.xml.dao.impl.UserDaoImpl"></bean>
自动装配方式:byName
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
<bean id="userController"class="com.atguigu.autowire.xml.controller.UserController" autowire="byName"> </bean> <bean id="userService"class="com.atguigu.autowire.xml.service.impl.UserServiceImpl" autowire="byName"> </bean> <bean id="userServiceImpl"class="com.atguigu.autowire.xml.service.impl.UserServiceImpl" autowire="byName"> </bean> <bean id="userDao" class="com.atguigu.autowire.xml.dao.impl.UserDaoImpl"> </bean> <bean id="userDaoImpl" class="com.atguigu.autowire.xml.dao.impl.UserDaoImpl"> </bean>