Spring之IoC
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之IoC相关的知识,希望对你有一定的参考价值。
- 什么是IOC
将对象的管理交给Spring容器,对象间的依赖进行解耦,想要某个对象,从Spring容器中进行获取
- IOC的类型
构造函数注入:Spring已经实现
成员变量注入:Spring已经实现
接口注入:Spring未实现
- 实现IOC的Java基础
反射技术等
Spring提供了比JDK更好的访问资源的API:Resource接口
/* * Copyright 2002-2016 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 * * http://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.core.io; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URL; /** * Interface for a resource descriptor that abstracts from the actual * type of underlying resource, such as a file or class path resource. * * <p>An InputStream can be opened for every resource if it exists in * physical form, but a URL or File handle can just be returned for * certain resources. The actual behavior is implementation-specific. * * @author Juergen Hoeller * @since 28.12.2003 * @see #getInputStream() * @see #getURL() * @see #getURI() * @see #getFile() * @see WritableResource * @see ContextResource * @see UrlResource * @see ClassPathResource * @see FileSystemResource * @see PathResource * @see ByteArrayResource * @see InputStreamResource */ public interface Resource extends InputStreamSource { /** * Determine whether this resource actually exists in physical form. * <p>This method performs a definitive existence check, whereas the * existence of a {@code Resource} handle only guarantees a valid * descriptor handle. */ boolean exists(); /** * Indicate whether the contents of this resource can be read via * {@link #getInputStream()}. * <p>Will be {@code true} for typical resource descriptors; * note that actual content reading may still fail when attempted. * However, a value of {@code false} is a definitive indication * that the resource content cannot be read. * @see #getInputStream() */ boolean isReadable(); /** * Indicate whether this resource represents a handle with an open stream. * If {@code true}, the InputStream cannot be read multiple times, * and must be read and closed to avoid resource leaks. * <p>Will be {@code false} for typical resource descriptors. */ boolean isOpen(); /** * Return a URL handle for this resource. * @throws IOException if the resource cannot be resolved as URL, * i.e. if the resource is not available as descriptor */ URL getURL() throws IOException; /** * Return a URI handle for this resource. * @throws IOException if the resource cannot be resolved as URI, * i.e. if the resource is not available as descriptor * @since 2.5 */ URI getURI() throws IOException; /** * Return a File handle for this resource. * @throws IOException if the resource cannot be resolved as absolute * file path, i.e. if the resource is not available in a file system */ File getFile() throws IOException; /** * Determine the content length for this resource. * @throws IOException if the resource cannot be resolved * (in the file system or as some other known physical resource type) */ long contentLength() throws IOException; /** * Determine the last-modified timestamp for this resource. * @throws IOException if the resource cannot be resolved * (in the file system or as some other known physical resource type) */ long lastModified() throws IOException; /** * Create a resource relative to this resource. * @param relativePath the relative path (relative to this resource) * @return the resource handle for the relative resource * @throws IOException if the relative resource cannot be determined */ Resource createRelative(String relativePath) throws IOException; /** * Determine a filename for this resource, i.e. typically the last * part of the path: for example, "myfile.txt". * <p>Returns {@code null} if this type of resource does not * have a filename. */ String getFilename(); /** * Return a description for this resource, * to be used for error output when working with the resource. * <p>Implementations are also encouraged to return this value * from their {@code toString} method. * @see Object#toString() */ String getDescription(); }
Resource接口演示
package org.zln.spring.resource; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Date; /** * Created by sherry on 16/10/13. */ public class SpringResourceDemo { private static Logger logger = LoggerFactory.getLogger(SpringResourceDemo.class); public static void main(String[] args) throws IOException { // test1(); String ss = "哇哈哈"; ByteArrayResource byteArrayResource = new ByteArrayResource(ss.getBytes("UTF-8")); } private static void test1() throws IOException { Resource resource = new ClassPathResource("log4j.properties"); logger.debug("exists:"+resource.exists()); logger.debug("isReadable:"+resource.isReadable()); logger.debug("getFile:"+resource.getFile().getAbsolutePath()); logger.debug("contentLength:"+resource.contentLength()); logger.debug("lastModified:"+new Date(resource.lastModified())); InputStream inputStream = resource.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"UTF-8")); for (String line = bufferedReader.readLine(); StringUtils.isNotEmpty(line);){ logger.info(line); line = bufferedReader.readLine(); } bufferedReader.close(); inputStream.close(); bufferedReader = null; inputStream = null; } }
- Resource的实现类
ByteArrayResource:二进制数组表示的资源,可以在内存中通过程序构造
String ss = "哇哈哈"; ByteArrayResource byteArrayResource = new ByteArrayResource(ss.getBytes("UTF-8"));
ClassPathResource:类路径下的资源
FileSystemResource:文件系统的资源
ServletContextResource:Web容器上下文的资源
UrlResource:URL表示的资源
Spring的Resource可以脱离Spring容器使用
- 资源的表达方式
classpath:、classpath:/,等价,都是从相对于classpath的根路径进行访问,只加载第一个
classpath*:扫描所有符合条件的文件
file:,UrlResource从文件系统获取
http://,web服务器
ftp://,ftp服务器
没有前缀,按照实现类的类型判断资源的形式
资源的表示形式支持Ant风格
? 任意一个字符
* 任意多个字符
** 多层路径
- 在XML中配置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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" 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/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <bean id="car" class="org.zln.beans.Car" p:brand="红旗CA72" p:color="黑色" p:maxSpeed="200"/> </beans>
初始化
package org.zln.beans; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by sherry on 16/7/5. */ public class BeanFactoryTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println("初始化Bean工厂"); Car car = (Car) applicationContext.getBean("car"); System.out.println(car); } }
- Java类配置Bean
package org.zln.beans; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Created by sherry on 16/7/5. */ @Configuration public class BeansConf { @Bean(name = "car") public Car carBuilder(){ Car car = new Car(); car.setBrand("红旗"); car.setColor("黑色"); car.setMaxSpeed(200); return car; } }
package org.zln.beans; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Created by sherry on 16/7/5. */ public class BeanFactoryTest { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeansConf.class); System.out.println("初始化Bean工厂"); Car car = applicationContext.getBean("car",Car.class); System.out.println(car); } }
- WebApplicationContext
该类是专门为Web环境准备的,允许从相对于Web根路径的位置加载Spring配置文件
WebApplicationContext可以获取ServletContext的引用,整个Web应用上下文对象将作为属性放置在ServletContext对象中,以便Web应用可以访问Spring应用上下文
Spring提供了一个工具类:WebApplicationContextUtils.getWebApplicationContext(ServletContext sc),用于获取WebApplicationContext实例
通过Web监听器启动Spring
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--① 启动Spring--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <!--② 启动Spring容器的监听,引用①处的上下文参数获取Spring配置文件地址--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
WebApplicationContext的启动需要用到日志功能,默认日志配置文件在classes根目录下
如果配置到了其他路径,则需要另外说明,并且保证在Spring框架启动前完成日志信息的装载
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> ...... <!--配置日志--> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j2.xml</param-value> </context-param> <!--通过监听装载日志配置文件--> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> ...... </web-app>
如果配置文件写在了Class类中,则需要如下配置才能启动
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </context-param> <!--① 启动Spring--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>Spring配置类的全限定名</param-value> </context-param> <!--配置日志--> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:log4j2.xml</param-value> </context-param> <!--通过监听装载日志配置文件--> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <!--② 启动Spring容器的监听,引用①处的上下文参数获取Spring配置文件地址--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--③ 配置Spring MVC地址映射--> <servlet> <servlet-name>bbt</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>bbt</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app> contextClass参数用于指定WebApplicationContext的实现类
<!--Spring解决乱码问题--> <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 将此配置在web.xml中
- 获取Spring容器的方法
1、定义工具类 public class SpringApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { SpringApplicationContextHolder.context = context; } public static Object getSpringBean(String beanName) { notEmpty(beanName, "bean name is required"); return context==null?null:context.getBean(beanName); } public static String[] getBeanDefinitionNames() { return context.getBeanDefinitionNames(); } } 2、注册工具类 将工具类在Spring中进行配置即可 3、使用工具类获取Spring管理的Bean 使用工具类的静态方法 getSpringBean 得到Bean实例
- 将Bean纳入Spring容器的三种方式
1、将Bean配置在类中,加上注解
2、将Bean配置在xml中
3、将Bean加上合适的注解,在xml中扫描
- 配置Bean之间依赖的几种方式
1、内部依赖使用内部bean(XML)
2、构造函数(XML、注解),优点:减少了setter方法,保证必须的依赖都初始化 缺点:初始化必须赋值,即使填null
3、成员变量(XML、注解),如果用注解,堪称完美
支持级联属性
支持集合属性的注入
使用util命名空间配置会方便很多
lookup方法注入
Bean之间的关系
如果多个Bean之间存在相同的配置信息,Spring允许我们定义父Bean,子Bean将自动继承父Bean的配置信息
父Bean如果不需要实例化的话,可以定义为抽象 abstract=“true”
依赖
depends-on 在xml配置后,优先实例化依赖的Bean
多个依赖使用逗号分隔
整合多个配置
xml使用import标签
注解配置
类:添加合适的注解
普通类:@Component
Dao:@Repository
Service:@Service
Controller:@Controller
XML:配置扫描路径
<context:component-scan base-package="org.zln" resource-pattern="**/*Dao.class"/>
<context:component-scan base-package="org.zln">
<context:include-filter type=“regex” expression=“”/> 需要包含的,可以配置多个
<context:exclude-filter type=“aspectj” expression=“”/> 需要排除的,可以配置多个
</context>
说明:
type:
annotation:expression填写某个注解,过滤出使用了这些注解的类
assignable:expression填写某个类或接口,过滤出扩展或继承了某个类的类
aspectj:这个比较强大
regex:类名满足正则表达式
custom:
将Bean被Spring扫描管理后,如何设置依赖呢?
1、在依赖的成员变量上添加 @Autowired注解(可以设置required属性规定是否必须从容器中获取到),表示通过类型进行依赖,可以同时添加@Qualifier 指明Bean的名称
2、在方法上添加@Autowired注解,会将对象注入给方法参数[email protected]注解可以添加到方法参数类型的前面
设置Bean的生命周期
在Bean中添加@Scope
在初始化执行的方法上,相当于xml中配置init-method的方法上,添加 @PostConstruct 容器关闭的时候,添加 @PreDestory 注解的方法会执行
- XML、注解、Java类,三种配置Bean的方式比较
XML:配置第三方类库,使用命名空间等
注解:自己写的一些类,尽量用注解+扫描的形式
Java类:初始化比较复杂的情况下使用
以上是关于Spring之IoC的主要内容,如果未能解决你的问题,请参考以下文章