spring框架详解系列(一)------常见的概念及基础知识

本问是对spring框架学习后对AOP,IoC.DI等核心概念的的总结性文档,对框架认识不足之处请各位前辈指正!!!
原创文章:转载请注明出处!!!

Spring框架概述

  1. Spring框架的概述
    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

  2. Spring的优点

方便解耦,简化开发 (高内聚低耦合)
Spring就是一个工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
spring工厂是用于生成bean,spring内部实现了FactoryBean工厂接口,用于创建对象(常见ApplicationContext对象就是该对象的子接口,功能比父接口更为强大)
AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
java源码学习的经典案例
是java面向对象的经典封装和反射技术应用的最佳范例

3.spring中常见的概念

IoC(Inverse of Control):反转控制
直白的讲,在使用spring框架之前,使用对象需要我们自己创建(new对象),使用该矿建后,对象的创建有工厂类,spring容器提供,我们只需要件的xml配置,使用时通过从容器中获取即可,对象创建的方式发生了反转。

DI(Dependency Injection):依赖注入
依赖注入是指,将值赋值给对象的一种技术,常见的依赖注入有set方式注入和构造方式注入。

总结:依赖注入是发展控制的必须条件。

BeanFactory对象和ApplicationContext对象
spring工厂类结构图如下
spring工厂类结构图
两者之间的根本区别:BeanFactory对象不会在容器启动时创建对象,而是在对象被调用时,才创建对象的实例
而ApplicationContext则在容器创建时加载创建所有配置的对象,使用时直接获取使用即可

AOP(aspect oriented programming)面向切面编程

AOP思想是spring对反射技术的具体体现,详细总结访问:https://blog.csdn.net/workingman_li/article/details/89484268

4.spring框架的体系结构
在这里插入图片描述

入门案例:(IoC)

导入jar包
4 + 2: 4个核心(beans、core、context、expression) + 1个依赖(commons-loggins…jar.由于spring框架的维护,4.2.4版本的spring还需要添加log4j日志包)

老版本
在这里插入图片描述
目标类
提供UserService接口和实现类
获得UserService实现类的实例
之前开发中,直接new一个对象即可。学习spring之后,将由Spring创建对象实例–> IoC 控制反转(Inverse of Control)
之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中

public interface UserService {
    public void addUser();
}
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("a_ico add user");
    }
}

配置文件
位置:任意,开发中一般在classpath下(src)
名称:任意,开发中常用applicationContext.xml
内容:添加schema约束
约束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\ xsd-config.html

<?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">
    <!-- 配置service 
        <bean> 配置需要创建的对象
            id :用于之后从spring容器获得实例时使用的
            class :需要创建实例的全限定类名
    -->
    <bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"></bean>
</beans>

2.4测试

   @Test
    public void demo02(){
        //从spring容器获得
        //1 获得容器
        String xmlPath = "com/itheima/a_ioc/beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
        //2获得内容 --不需要自己new,都是从spring容器获得
        UserService userService = (UserService) applicationContext.getBean("userServiceId");
        userService.addUser();  

3 入门案例:DI
例如:

class BookServiceImpl{
    //之前开发:接口 = 实现类  (service和dao耦合)
    //private BookDao bookDao = new BookDaoImpl();
    //spring之后 (解耦:service实现类使用dao接口,不知道具体的实现类)
    private BookDao bookDao;
    setter方法
}

模拟spring执行过程
创建service实例:BookService bookService = new BookServiceImpl() -->IoC
创建dao实例:BookDao bookDao = new BookDaoImple() -->IoC
将dao设置给service:bookService.setBookDao(bookDao); -->DI

目标类
创建BookService接口和实现类
创建BookDao接口和实现类
将dao和service配置 xml文件
使用api测试
dao实现

//接口
public interface BookDao {
    public void save();
}
//实现类
public class BookDaoImpl implements BookDao {

    @Override
    public void save() {
        System.out.println("di  add book");
    }
}

service层

public interface BookService {
    public abstract void addBook();
}
//实现类
public class BookServiceImpl implements BookService {

    // 方式1:之前,接口=实现类(不适用)
//  private BookDao bookDao = new BookDaoImpl();
    // 方式2:接口 + setter
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void addBook(){
        this.bookDao.save();
    }

}

配置文件

<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">
    <!-- 
    模拟spring执行过程
        创建service实例:BookService bookService = new BookServiceImpl() IoC  <bean>
        创建dao实例:BookDao bookDao = new BookDaoImpl()         IoC
        将dao设置给service:bookService.setBookDao(bookDao);     DI   <property>

        <property> 用于进行属性注入
            name: bean的属性名,通过setter方法获得
                setBookDao ##> BookDao  ##> bookDao
            ref :另一个bean的id值的引用
     -->

    <!-- 创建service -->
    <bean id="bookServiceId" class="com.itheima.b_di.BookServiceImpl">
        <property name="bookDao" ref="bookDaoId"></property>
    </bean>

    <!-- 创建dao实例 -->
    <bean id="bookDaoId" class="com.itheima.b_di.BookDaoImpl"></bean>
</beans>

3.5 测试

@Test
public void demo01(){
    //从spring容器获得
    String xmlPath = "com/itheima/b_di/beans.xml";
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) applicationContext.getBean("bookServiceId");    
    bookService.addBook();

实例来源原文:https://blog.csdn.net/qq_22583741/article/details/79589910

IoC中Bean标签管理对象的实现细节

Bean元素属性详细`

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入beans约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/beans" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    
	<!-- user对象 -->
	<!-- bean元素: 配置需要spring创建|管理的对象
			name属性:给spring管理的对象起个"别名".获得对象时根据该名称获得对象.(可选)
			id属性:给spring管理的对象起个"别名".获得对象时根据该名称获得对象.(可选)
			class属性: 完整类名
			scope属性:指定对象的作用域(生命周期)
				*singleton:(默认值)单例对象.整个spring容器范围内,单例对象只会被创建一次.单例对象会在容器启动时创建
				*prototype:原型的.每次获得对象时都会创建新的对象.
				request: 在web环境下,确保每次请求都会创建一个新的对象
				session: 在web环境下,确保每次会话都会创建一个新的对象
				global-session:在web集群环境下,确保每个集群共享session范围内都会创建一个新的对象
			init-method&destroy-method属性: 指定初始化方法|销毁方法
	  -->
	<bean name="user" class="cn.itcast.domain.User" scope="singleton" init-method="init" destroy-method="destory" >
		<property name="name" value="tom"></property>
		<property name="age" value="18"></property>
	</bean>
	<!-- 引入其他配置 -->
	<import resource=".../di.xml"/>
</beans>

实例化Bean的三种方式

一、构造方法实例化Bean对象(不常用)

在相应的实体类中提供空参构造和有参构造集合

public class User {

    private Integer uid;
    private String username;
    private Integer age;

    public User(Integer uid, String username) {
        super();
        this.uid = uid;
        this.username = username;
    }

    public User(String username, Integer age) {
        super();
        this.username = username;
        this.age = age;
    }

xml配置

   <!-- 构造方法注入 
        * <constructor-arg> 用于配置构造方法一个参数argument
            name :参数的名称
            value:设置普通数据
            ref:引用数据,一般是另一个bean id值

            index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
            type :确定参数类型
        例如:使用名称name
            <constructor-arg name="username" value="jack"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
        例如2:【类型type 和  索引 index】
            <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
            <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    -->
    <bean id="userId" class="com.itheima.f_xml.a_constructor.User" >
        <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
        <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
    </bean>

二、调用静态工厂方法和动态工厂创建Bean
创建工厂类

public class UserFactory {
	//动态工厂方法
		public  User getUser2(){
				System.out.println("User动态工厂方法");
				return new User();
		}
		
	//静态工厂方法
	public static User getUser1(){
		System.out.println("User静态工厂方法");
		return new User();
	}

}

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    
	<!-- 静态工厂方法
			让spring调用com.huawei.factory.UserFactory的getUser1方法创建user1对象
	 -->
	<bean name="user1" class="com.huawei.factory.UserFactory" factory-method="getUser1" >
		<property name="name" value="tom"></property>
		<property name="age" value="18"></property>
	</bean>
	<!-- 动态工厂方法
	 -->
	 <!-- 创建工厂对象 -->
	 <bean name="userFactory" class="com.huawei.factory.UserFactory" ></bean>
	 <!-- 调用userFactory对象的getUser2方法创建user2对象 -->
	<bean name="user2" factory-bean="userFactory" factory-method="getUser2" >
		<property name="name" value="jerry"></property>
		<property name="age" value="16"></property>
	</bean>
</beans>

测试方法

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.huawei.domain.User;

public class Demo {
	@Test
	public void fun1(){
		
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/huawei/factory/factory.xml");
		
		User bean1 = (User) ac.getBean("user1");
		User bean2 = (User) ac.getBean("user1");
		
		System.out.println(bean1);
		System.out.println(bean1==bean2);
		
		ac.close();
	}
	
	@Test
	public void fun2(){
		
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/huawei/factory/factory.xml");
		
		User bean1 = (User) ac.getBean("user2");
		User bean2 = (User) ac.getBean("user2");
		
		System.out.println(bean1);
		System.out.println(bean1==bean2);
		
		ac.close();
	}
}

三、依赖注入
简单属性注入
1.构造方法注入
2.gettersetter方法注入
3.P名称空间

xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:p="http://www.springframework.org/schema/p" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    <!-- 构造方法注入 -->
	<bean name="user1" class="com.huawei.domain.User" >
		<!-- constructor-arg : 代表构造方法的一个参数
			  定位属性:	
				name属性:参数名
				index属性:指定参数在参数列表中的索引(位置),从0开始(确定构造函数的重载)
				type属性:指定参数的类型
			 赋值属性:
				value属性:参数值
				ref属性:注入对象类型值
		 -->
		<constructor-arg name="name" value="jack" index="0" ></constructor-arg>
		<constructor-arg name="age" value="18" type="java.lang.Integer" ></constructor-arg>
		<constructor-arg name="car" ref="car" ></constructor-arg>
	</bean>
	<!-- ###################################################################### -->
	<!-- set方法注入 -->
	
	<!-- property标签 -->
	<bean name="user2" class="com.huawei.domain.User" >
		<!-- property标签:代表一个set方法 -->
		<property name="name" value="rose" ></property>
		<property name="age" value="20" ></property>
		<property name="car" ref="car" ></property>
	</bean>
	<!-- ###################################################################### -->
	<!-- p名称空间注入(与property标签注入只有写法的区别)
		准备工作: xmlns:p="http://www.springframework.org/schema/p"
	 -->
	<bean name="user3" class="xom.huawei.domain.User"
			 p:name="tom" p:age="18" p:car-ref="car" ></bean>
<!-- ###################################################################### -->
	<!-- SPEL表达式
			语法: #{表达式}
			作用:使用已有对象的属性值初始化化对象,该表达式获取容器中的对象的属性值
	 -->
	<bean name="user4" class="xom.huawei.domain.User" >
		<property name="name" value="#{user2.name}"></property>
		<property name="age" value="#{user3.age}"></property>
		<!-- 对象类型属性无法使用spel -->
		<property name="car" ref="car" ></property>
	</bean>
	
	<!-- car对象 -->
	<bean name="car" class="com.huawei.domain.Car" >
		<property name="name" value="兰博基尼" ></property>
	</bean>
</beans>

复杂属性注入
1.注入数组
2.注入 List
3.注入Map

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://www.springframework.org/schema/beans" 
		xmlns:p="http://www.springframework.org/schema/p" 
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
	
	<!-- 复杂类型注入(set方法注入) -->
	<bean name="cb" class="com.huawei.domain.CollectionBean" >
		<!-- 情况1: 数组中只需要注入一个值(对象),直接将数组当做简单类型属性使用
						<property name="arr" ref="car" ></property>
		 	 情况2:数组中需要注入多个值|对象
		 -->
		<property name="arr"  >
			<array>
				<value>tom</value>
				<value>jerry</value>
				<ref bean="car" />
			</array>
		</property>
		<!-- 情况1: List中只需要注入一个值(对象),直接将List当做简单类型属性使用
					
					 <property name="list" ref="car" ></property>
		 	 	情况2:List中需要注入多个值|对象
					
		 -->
		 			<property name="list"  >
						<list>
							<value>tom</value>
							<value>jerry</value>
							<ref bean="car" />
						</list>
					</property>
		<!-- map注入 -->
			<property name="map">
				<map>
					<!-- 一个entry代表一个键值对 -->
					<entry key="name" value="tom" ></entry>
					<entry key-ref="car" value="hehe" ></entry>
					<entry key="haha" value-ref="car" ></entry>
				</map>
			</property>
		<!-- properties注入 => 是一个只能存放字符串类型的键值对的容器 -->
		<property name="props">
			<props>
				<!-- 一个prop就代表一个键值对 -->
				<prop key="haha">hehe</prop>
				<prop key="xixi">heihei</prop>
				<prop key="gaga">hiahia</prop>
			</props>
		</property>
	</bean>

	<!-- car对象 -->
	<bean name="car" class="com.huawei.domain.Car" >
		<property name="name" value="兰博基尼" ></property>
	</bean>
</beans>

以上配置的实体类

public class User {

	public User(String name) {
		System.out.println("public User(String name)!");
		this.name = name;
	}

	public User(Integer age) {
		System.out.println("public User(Integer age)!");
		this.age = age;
	}
	
	public User(String name, Integer age) {
		System.out.println("public User(String name, Integer age)!");
		this.name = name;
		this.age = age;
	}
	
	public User(String name, Long age) {
		System.out.println("public User(String name, Long age)!");
		this.name = name;
		this.age = age.intValue();
	}
	public User(Integer age,String name) {
		System.out.println("public User(Integer age,String name)!");
		this.name = name;
		this.age = age;
	}
	public User(String name, Integer age, Car car) {
		System.out.println("public User(String name, Integer age, Car car)!");
		this.name = name;
		this.age = age;
		this.car = car;
	}

	public User() {
		System.out.println("user 的空参构造!");
	}

	private String name;
	
	private Integer age;
	
	private Car car;

//getter和setter方法

	public void init(){
		System.out.println("我是初始化方法!");
	}
	public void destory(){
		System.out.println("我是销毁方法!");
	}
}

实体类:car类

public class Car {
	private String  name;
	//getter、setter方法
}

实体类:CollectionBean

public class CollectionBean {
	private Object[] arr;
	private List list;
	private Map map;
	private Properties props;
	
    //get和set方法
}

其他当时的引入
如import标签映入:

//引入其他配置文件中的对象
<import   resource ="com.huawei.Customer" />

IoC注解

导包(4+2)+aop包
spring-aop-4.2.4.RELEASE.jar 该包为aop相关核心包

1.在xml中导入context约束
2.在配置文件中添加组件扫描的标签

相关的约束
<!-- 开启IOC注解开关 
			如果需要扫描多个包
				方式1: 包名,包名,包名.......
				方式2: cn.itcast => 包含所有后代包
	-->    
 <context:component-scan base-package="com.huawei"></context:component-scan>

基于注解装配Bean(依赖注入)

开发中:使用注解 取代 xml配置文件。前提是配置包扫描器 (组件扫描器)

1.@Component取代
@Component(“id”) 取代
2.web开发,提供3个@Component注解衍生注解(功能一样)代替其表示各层
@Repository :dao层
@Service:service层
@Controller:web层
3.依赖注入,给私有字段设值,也可以给setter方法设值

普通值:@Value(" ")
引用值:
方式1:按照【类型】注入
@Autowired

注意:该方式是对方法属性注入,只按照set方法名注入,与字段无关(开发阅读源码是注意)

方式2:按照【名称】注入1
@Autowired
@Qualifier(“名称”)
方式3:按照【名称】注入2
@Resource(“名称”)
4.生命周期
初始化:@PostConstruct
销毁:@PreDestroy
5.作用域
@Scope(“prototype”) 多例 ,如struts2的action需设置此属性
value取值为prototype/singleton 多列/单例,一般可省略value不写,直接写值

参考文章链接:
Spring框架介绍及使用:https://blog.csdn.net/qq_22583741/article/details/79589910

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值