目录标题
- 一、Spring简单介绍
- 1.1、Spring框架的作用
- 1.2、了解
- 1.3、优点
- 二、控制反转(IOC)
- 2.1、何为控制反转
- 2.2、程序主动创建类对象(原来的方式)
- 2.3、使用IOC的设计思想(革命性改变)
- 2.4、IOC的本质
- 2.5、第一个Spring程序
- 2.6、IOC创建对象的方式
- 三、Spring配置说明
- 3.1、bean标签
- 3.2、alias标签
- 3.3、import标签
- 3.4、bean的作用域
- 四、依赖注入
- 4.1、通过构造器注入
- 4.2、一般的注入方式(set方法注入)
- 4.3、拓展注入
- 五、bean的自动装配
- 5.1、Spring中bean的装配方式
- 六、使用java来配置Spring(先放放)
- 七、面向切面编程(AOP)
一、Spring简单介绍
1.1、Spring框架的作用
- 它的理念就是为了解决软件开发的复杂性,实现有的技术能够更加容易使用
- 它的出现给软件行业带来了“春天”
1.2、了解
- SSH:Struts2+Spring+Hibernate(反正我在校期间,就学的这套)
- SSM:SpringMVC+Spring+Mybatis
1.3、优点
- Spring是一个开源免费的框架,也可以说是一个容器,可以把什么“东西”都可以放进去(“大杂烩”)
- Spring是一种轻量级、非入侵式的框架(非入侵式就是可以在里面随意导入任何项目)
- 最重要的两个特性:控制反转(IOC)、面向切面编程(AOP)
- 支持对事务的处理和对框架的整合
二、控制反转(IOC)
2.1、何为控制反转
- 控制反转IoC(Inversion of Control),它是一种设计思想
- 控制反转就是由原来的的程序主动创建类对象,转变为程序被动创建类对象(可能不太好理解)
下面给出一个例子:
2.2、程序主动创建类对象(原来的方式)
通过这个例子,我们可以发现:如果按照传统的编程设计思想,那么如果用户的业务需求发生了改变,会出现一种情况:
需要在service业务层的接口实现类里面去进行再次更改,来创建新的Dao层接口实现类对象,比如:(这里可能不太好理解)
private UserDao userDao = new UserDaoImpl();
private UserDao userDao = new UserDaoMysqlImpl();
- dao层
//Dao层接口
package com.my.dao;
public interface UserDao {
void getUser();
}
//Dao层接口实现类
package com.my.dao;
public class UserDaoImpl implements UserDao{
public void getUser() {
System.out.println("默认获取用户数据!");
}
}
//Dao层接口实现类
package com.my.dao;
public class UserDaoMysqlImpl implements UserDao{
public void getUser(){
System.out.println("Mysql获取用户数据");
}
}
- service层
//业务层接口
package com.my.service;
public interface UserService {
void getUser();
}
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
public void getUser(){
userDao.getUser();
}
}
- 测试
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际上调用的是业务层,dao层用户不需要接触
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
2.3、使用IOC的设计思想(革命性改变)
在上述例子的基础上,我们在业务层接口实现类中的定义一个set方法
- service层改变
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;
public class UserServiceImpl implements UserService{
/*
* 关键:(要理解)
* */
// private UserDao userDao = new UserDaoImpl();
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
private UserDao userDao;
//利用set方法进行动态的实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser(){
userDao.getUser();
}
}
- 测试执行
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际上调用的是业务层,dao层用户不需要接触
UserService userService = new UserServiceImpl();
//在此处体会其中的作用
((UserServiceImpl)userService).setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
上述例子就是控制反转(IOC)的原型
2.4、IOC的本质
- 是一种设计思想,而实现这种思想的方式有很多,常见的就是依赖注入(DI)
- 控制反转其实就是获取类对象的方式发生了改变
2.5、第一个Spring程序
- 实体类
package com.my.pojo;
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- Spring配置文件(beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用Spring来创建对象,每个对象都是bean
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 变量名
class:new的对象
property:相当于给对象中的属性设置一个值
-->
<bean id="hello" class="com.my.pojo.Hello">
<property name="name" value="Spring !"></property>
</bean>
</beans>
- 测试执行
import com.my.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象(可以同时加载多个配置文件)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象都在Spring中,我们要使用直接从里面取出来就行
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello.toString());
}
}
总结:
- 控制:谁来控制对象的创建?原来是程序本身,现在是Spring容器
- 反转:原来是程序主动创建对象,现在变成被动的接收对象
- 这就是控制反转的思想
2.6、IOC创建对象的方式
- 通过实体类的无参构造方法创建类对象(默认的)
通过这种方式,可以验证:在配置文件被加载后,Spring容器里面的对象就已经被初始化了如图所示:
- 通过实体类的有参构造方法创建类对象(又分为三种)
1、通过下标的方式
<bean id="user" class="com.my.pojo.User">
<constructor-arg index="0" value="马老师"/>
</bean>
2、通过参数的类型(不建议使用)
<bean id="user" class="com.my.pojo.User">
<constructor-arg type="java.lang.String" value="马老师"/>
</bean>
3、通过参数名
<bean id="user" class="com.my.pojo.User" name="user2,user3 user4">
<constructor-arg name="name" value="马老师"/>
</bean>
参照实体类User:
package com.my.pojo;
public class User {
private String name;
public User(){
System.out.println("默认的构造方法!");
}
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+name);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
总结:
- 通过无参方式创建对象,给实体类属性赋值使用property标签
- 通过有参方式创建对象,给实体类属性赋值统一使用constructor-arg标签
- 注意:bean标签里面有个name属性,可以给id进行重命名,甚至可以重命名多个,之间用逗号,空格,分号分开(都行)
三、Spring配置说明
3.1、bean标签
- id:bean的唯一标识符,也就是相当于创建的对象名
- class:bean对象所对应的全限定名(包名+类名)
- name:给id去别名,上面也提到了使用规范
- property子标签:给对象中的属性设置一个值
3.2、alias标签
就是用来给id去别名,但一般以及被其name属下取代
3.3、import标签
合并配置文件
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
3.4、bean的作用域
bean的有两个常用的作用域:
- singleton单例模式:(Spring默认的)
- prototype原型模式:每次从容器中去拿同一实体类对象的时候,就是每次去get的时候,拿到的都是新对象!(理解)
示例:
<bean id="user" class="com.my.pojo.User" p:name="马老师" p:age="22" scope="prototype"/>
四、依赖注入
4.1、通过构造器注入
参考上面的IOC创建对象方式
4.2、一般的注入方式(set方法注入)
依赖:bean“对象”的创建依赖Spring容器
注入:类对象的属性由容器注入
这里几乎包含了所有数据类型的注入方式:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.my.pojo.Address"/>
<bean id="student" class="com.my.pojo.Student">
<!--普通值注入,value-->
<property name="name" value="马老师"/>
<!--bean(类对象)注入,ref-->
<property name="address" ref="address"/>
<!--数组注入,array-->
<property name="books">
<array>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
<value>红楼梦</value>
</array>
</property>
<!--list注入,list-->
<property name="hobbys">
<list>
<value>打游戏</value>
<value>听歌</value>
<value>编程</value>
</list>
</property>
<!--map注入,map-->
<property name="score">
<map>
<entry key="语文" value="90"/>
<entry key="数学" value="100"/>
</map>
</property>
<!--null注入,null-->
<property name="wife">
<null/>
</property>
<!--null注入,null-->
<property name="info">
<props>
<prop key="driver">xxxxx</prop>
<prop key="url">xxxxx</prop>
</props>
</property>
</bean>
</beans>
4.3、拓展注入
使用p/c命名空间
<?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"
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">
<!--p命名空间注入,可以直接注入属性的值 property-->
<bean id="user" class="com.my.pojo.User" p:name="马老师" p:age="22"/>
<!--c命名空间注入,通过构造器来注入属性的值 constructor-args-->
<bean id="user2" class="com.my.pojo.User" c:name="马老师" c:age="19"/>
</beans>
注意:使用这两个命名空间前,需要添加约束!
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
五、bean的自动装配
5.1、Spring中bean的装配方式
1、xml的显示配置
- byName:根据bean的id属性来匹配类对象(id的取值需是setXx方法中的Xx,那么一个类也就一个bean)
- byType:根据类的全限定名来匹配类对象(一个类只能在配置文件中对应一个bean)
示例:
<bean id="cat" class="com.my.pojo.Cat"/>
<bean id="dog" class="com.my.pojo.Dog"/>
<bean id="people" class="com.my.pojo.People" autowire="byName">
<property name="name" value="马老师"/>
<!-- 不在使用这种装配方式-->
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
2、java代码中的显示配置(它们注解底层也是基于byName和byType的方式)
- 使用@Autowired注解来实现,详解参考:@Autowired详解
- 使用@Resource注解(和@Autowired注解类似)
执行顺序不同:@Autowired默认先通过byType的方式实现,@Resource默认先通过byName方式实现
注意:使用注解进行自动装配时,需要在配置文件里面导入约束和开启注解支持
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解支持!-->
<context:annotation-config/>
</beans>
3、隐式的自动装配(使用注解开发)
- @Component注解相当于:
<bean id="user" class="com.my.pojo.User"/>
, 放在实体类的类名前面 - @Value注解用于给实体类的属性赋值,相当于:
<property name="name" value="马老师"/>
, 放在属性上或者属性对应的setXx方法上都可以 - @Component注解有几个衍生注解,我们在web开发中,会按照mvc架构进行分层
dao层:@Repository
service层:@Service
controller层:@Controller
- @Scope注解:用来设置实体类的单例模式、原型模式等
注意:在使用注解开发时,不仅需要开启注解支持,还要指定要扫描的包,只有这样该包下的注解才会生效
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.my"/>
<!--开启注解支持!-->
<context:annotation-config/>
六、使用java来配置Spring(先放放)
七、面向切面编程(AOP)
在学习面向切面编程之前,需要先了解什么是代理模式,以及静态代理和动态代理的工作原理和它们之间的区别。
静态代理:需要新建一个代理类(好处,不仅能实现需要完成的业务,还能够随时增添新的业务)
动态代理:调用处理程序,可以根据任意接口来动态生成对应的代理对象
静态代理:
- 优点:随时增加新的业务,方便管理
- 缺点:实际应用需要多个代理对象,代码量翻倍开发效率降低
具体实现过程参考学习笔记!