Spring 是一个主流的 Java Web 开发框架,该框架是一个轻量级的、非入侵式的应用框架,可以解决企业应用开发的复杂性。
Spring 以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核:
Spring 特点:
(1)方便解耦,简化开发
(2)Aop 编程支持
(3)方便程序测试
(4)方便和其他框架进行整合。通常服务器端采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。Spring 对每一层框架都提供了技术支持,在表现层提供了与 Struts2 框架的整合,在业务逻辑层可以管理事务和记录日志等,在持久层可以整合Mybatis、 Hibernate 和 JdbcTemplate 等技术。
(5)方便进行事务操作
(6)降低API 开发难度
为什么需要Bean容器?
一般的项目搭建,都需要将各层进行分离以降低代码之间的耦合度。比如我们常用Dao层(数据访问层)、service层来封装和数据库的交互部分,其中Dao层负责具体的增删查改,service层负责调用Dao层的方法来对外提供服务,即用户只需要调用业务层,不需要接触Dao层。例如:
使用这种方法相当于将对象创建放到了方法中,此时对象对应的变量(局部变量)随着栈帧的创建而出现,随着栈帧的退出而销毁。那么由于没有引用指向它,该对象就会很快变成可回收状态。如果对象的创建初始化较为复杂,那么此处的对象创建就会变得效率低下。所以这种方法存在对象创建销毁的问题,极大的影响了效率,且当Dao层增加代码时,业务层也要随之改变,所以我们应该去寻求一种用户只管调用,业务层无需程序员更改的一种模式。
针对以上问题我们可以用Bean容器来解决,类似于下面的形式,将对象交给Spring来管理:
Spring相关jar包:
为了方便使用Spring,我们可以使用maven:我们只需要导入一个spring-webmvc就好了,因为spring-webmvc依赖了很多其他的包。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.10.RELEASEversion>
dependency>
spring的核心依赖项基本上都包含在spring-webmvc中了。
官方文档
(1)控制反转
(2)使用IOC 目的:
(3) Spring 容器高层视图
Spring 启动时读取Bean 配置信息,并在Spring 容器中生成一份相应的Bean 配置注册表,然后根据这张注册表实例化Bean,装配好Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。其中Bean 缓存池为HashMap 实现.
Spring容器在初始化时先读取配置文件,根据配置文件或者元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
IOC 思想基于IOC 容器完成,IOC 容器底层就是对象工厂
IOC 容器两种对象工厂实现方式:(两个接口)
注意:
1)在spring 配置文件中,使用bean 标签,标签里面添加对应属性,就可以实现对象创建
2)在bean 标签有很多属性,介绍常用的属性
3)创建对象时候,默认执行无参数构造方法完成对象创建
依赖注入(Dependency Injection,DI):注入属性,在Spring中实现控制反转的是Ioc容器,其具体实现方法就是依赖注入。
IOC和DI的区别:
1)第一种注入方式:使用set 方法进行注入
利用对象方法中的set方法进行注入,方法中要包含应该有的setter方法。 如果属性注入时,对应的属性没有set方法,那么xml对应的bean中属性名会报错。
(1)创建类,定义属性和对应的set 方法
public class Book {
//创建属性
private String name;
private String author;
//创建属性对应的set方法
public void setBname(String name) {
this.name = name;
}
public void setBauthor(String author) {
this.author = author;
} }
(2)在spring 配置文件配置对象创建,配置属性注入
<bean id="book" class="com.atguigu.spring5.Book">
<property name="bname" value="易筋经">property>
<property name="bauthor" value="达摩老祖">property>
bean>
2)第二种注入方式:使用有参数构造进行注入
使用有参构造函数时,对应属性可以不用写set方法。
(1)创建类,定义属性,创建属性对应有参数构造方法
public class Orders {
//属性
private String oname;
private String address;
//有参数构造
public Orders(String oname,String address) {
this.oname = oname; this.address = address;
}
}
(2)在spring 配置文件中进行配置
<bean id="orders" class="com.atguigu.spring5.Orders">
<constructor-arg name="oname" value="电脑">constructor-arg>
<constructor-arg name="address" value="China">constructor-arg>
bean>
注:有参构造方法有三种传参方式:
下标:
类型:
参数名:
3)第三种注入方式:工厂注入属性
参考博客:Spring工厂注入属性
4)第四种注入方式p命名空间:对应set属性注入
需要在beans的首部加入xmlns:p="http://www.springframework.org/schema/p"
传统属性注入
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
P命名空间直接进行属性注入:
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
5)第五种注入方式c命名空间:对应构造器注入
需要在beans的首部加入xmlns:c="http://www.springframework.org/schema/c"
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
传统构造器注入
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
</bean>
c命名空间使用:
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="[email protected]"/>
注:
p命名和c命名不能直接使用,需要导入xml约束。
7)空值、null 值、特殊符号注入:
空值注入:
<property name="ducks2" value=""/>
null值注入:
<property name="address"> <null/> property>
包含特殊符号的属性值:把带特殊符号内容写到CDATA
<property name="address">
<value>>]]>value> property>
输出:User{address='<<南京>>', age=0}
8)注入属性-外部bean-内部bean-级联赋值
参考博客:https://blog.csdn.net/glpghz/article/details/109727241
9)xml 注入集合属性
数组array:
<property name="nums">
<array>
<value> 1</value>
<value> 2</value>
</list>
</property>
list:
<property name="duck">
<list>
<ref bean="duck1" />
<ref bean="duck2" />
</list>
</property>
map:
<property name="ducks1">
<map>
<entry key="" value=""/>
<entry key="" value=""/>
</map>
</property>
set:
<property name="ducks2">
<set>
<value> 1</value>
<value> 2</value>
</set>
</property>
普通bean:在配置文件中定义bean 类型就是返回类型
工厂bean(FactoryBean):在配置文件定义bean 类型可以和返回类型不一样
1)第一步创建类,让这个类作为工厂bean,实现接口FactoryBean
2)第二步实现接口里面的方法,在实现的方法中定义返回的bean 类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
xml配置:
<bean id="myBean"
class="com.atguigu.spring5.factorybean.MyBean"> bean>
测试:
@Test
public void test3() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
Bean 定义了5 中作用域,分别为
1) singleton:单例模式(多线程下不安全)
Spring IoC 容器中只会存在一个共享的Bean 实例,无论有多少个
Bean 引用它,始终指向同一对象。
2)prototype:原型模式每次使用时创建
每次通过Spring 容器获取prototype 定义的bean 时,容器都将创建
一个新的Bean 实例,每个Bean 实例都有自己的属性和状态,而singleton 全局只有一个对象。根据经验,对有状态的bean 使用prototype 作用域,而对无状态的bean 使用singleton作用域。
注:
ThreadLocal
进行处理,让它们也成为线程安全的状态,因此有状态的Bean就可以在多线程中共享了。3)Request:一次request 一个实例
在同一个Http 请求中,容器会返回该Bean 的同一实例。而对不同的Http 请求则会产生新的Bean,而且该bean 仅在当前Http Request 内有效,当前Http 请求结束,该bean实例也将会被销毁。
bean 的后置处理器,bean 生命周期有七步
1)通过构造器创建bean 实例(无参数构造)
2)为bean 的属性设置值和对其他bean 引用(调用set 方法)
3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
4)调用bean 的初始化的方法(需要进行配置初始化的方法)
5)把bean 实例传递bean 后置处理器的方法postProcessAfterInitialization
6)bean 可以使用了(对象获取到了)
7)当容器关闭时候,调用bean 的销毁的方法(需要进行配置销毁的方法)
创建后置处理器:创建类,实现接口BeanPostProcessor
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;
}
}
当这个类实现了BeanPostProcessor,并注入到Bean容器中后,Spring就会识别出这个后置处理器,并将该后置处理器置于每个Bean的生命周期中。
参考博客:Spring生命周期——简介
根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入。
1)注入属性时根据属性名称自动注入
员工类Emp中有一个部门dept属性
<bean id="emp" class="com.atguigu.spring5.autowire.Emp"
autowire="byName">bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept">bean>
2)注入属性时根据属性类型自动注入
员工类Emp中有一个部门dept属性,类型为Dept
<bean id="emp" class="com.atguigu.spring5.autowire.Emp"
autowire="byType"> bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept">bean>
把外部properties 属性文件引入到spring 配置文件中
1)引入context 名称空间
2)使用context标签引入外部属性文件jdbc.properties
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}">property>
<property name="url" value="${prop.url}">property>
<property name="username" value="${prop.userName}">property>
<property name="password" value="${prop.password}">property>
bean>
applicationContext.xml中的常用配置:
:
用来容纳一些bean对象 :
用来定义bean对象
:用来合并xml,将其他xml中的bean对象导入进来。 :
用来给bean对象起别名
:可以直接在bean中用name起别名,而且可以起多个别名,中间用空格,逗号分割都可以。1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
2)使用注解,注解作用在类上面,方法上面,属性上面
3)使用注解目的:简化xml 配置
1)@Component
可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。
2)@Repository
用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
3)@Service
通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
4)@Controller
通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
5)@Configuration:声明当前类是一个配置类,相当于一个Spring配置的xml文件。把一个类作为一个IoC容器和@Bean搭配使用,某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
6) @Bean:表示注册一个名称为方法名的Bean对象到容器中。此时方法的名称就相当于bean标签中的id属性,方法返回值就相当于bean标签中的class属性。
@Bean(name="aservice")
7)@Import(config.class):可以引入一个配置类,将两个配置类整合到一起。
8) @ComponentScan(com.glp.config) : ComponentScan做的事情就是告诉Spring从哪里找到bean.哪些包需要被扫描, 一旦指定好之后Spring将会将在被指定的包及其下级的包(sub packages)中寻找bean。
@ComponentScan(com.glp.config)
public class config{
}
9) @Scope(“prototype”): 原生模式,不加的话默认就是单例模式。
注意:
@Component 、@Repository 、@Service
只是用来分层没有具体的含义。 @Controller
是用于做客户端请求的层。说明:
在使用@Bean(name=“bean1”)给注册对象起别名时,可以用Bean的name属性,或者@Qualifier.
@Bean(name="bean1")
public A getA() {
return new A();
}
@Bean
@Qualifier("bean2")
public A getB() {
return new A();
}
使用时可以用 @Qualifier通过名称从容器中引入:
@Autowire
@Qualifier("bean1")
A testa;
1)第一步 引入依赖
spring-aop-5.2.6.RELEASE.jar
2)第二步 开启组件扫描:将包中含有注解的组件注入到容器中
<context:component-scan base-package="com.atguigu">
context:component-scan>
3)第三步创建类,在类上面添加创建对象注解
@Component(value = "userService")
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
注意:
filter context:include-filter ,设置扫描哪些内容
<context:component-scan base-package="com.atguigu"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
context:exclude-filter:设置哪些内容不进行扫描
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
注意:
use-default-filters="false"
表示现在不使用默认filter,自己配置
1)@Autowired:根据属性类型进行自动装配
第一步把service 和dao 对象创建,在service 和dao 类添加创建对象注解
第二步在service 注入dao 对象,在service 类添加dao 类型属性,在属性上面使用注解
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
} }
注:
不需要添加set方法
2)@Qualifier:根据名称进行注入
@Qualifier 注解需要和上面@Autowired 一起使用
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
3)@Resource:可以根据类型注入,可以根据名称注入
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
注:
默认根据类型注入
@Bean所在的方法user2,要使用user1,可以用方法参数的方式注入,使用@Qualifier("user1")
指明要使用的Bean对象。
@Bean
public User user2(@Qualifier("user1") User user1){};
4)@Value:注入普通类型属性
@Value(value = "abc")
private String name;
@value("glp")
public void setName(String name){
this.name =name;
}
1)创建配置类,替代xml配置文件
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
@Bean
public User user(){
//定义了一个名称为方法名user1的user对象,并注册到容器中
User user = new User();
user.setUsername("烤鸭1");
user.setPassword("123");
user.setBirthday(new Date());
return user;
}
}
相当于在xml中配置了一个User对象
2)编写测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService =
context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
注:
ApplicationContext有两个实现类,一个ClassPathXmlApplicationContext
用来获取xml中的Bean,一个AnnotationConfigApplicationContext
用来获取注解中的Bean.
ApplicationContext Context = new AnnotationConfigApplicationContext(Test.class);
User user = (User)Context.getBean("getUser");
参考博客:Spring框架的核心组件——Aop
参考博客:Spring——JdbcTemplate
参考博客:Spring——事务管理