1.Spring的基本介绍
spring:从翻译来说是春天的意思,意思是给软件开发带来了春天(想象下春天的美好~),spring的作者的初衷是让现有的技术更加实用,不是创造轮子,而是使轮子更好的运转。他就是一个大杂烩,整合了现有的技术
spring的优点
1.轻量级框架,不具有侵入性,方便框架的整合;
2.IOC容器:控制反转;
3.AOP:面向切面编程;
4.对事务的支持;
spring的主要内容
image.png- Test:spring支持Junit单元测试
- 核心容器(IOC):Bean(Bean工厂,创建对象),Core(核心,一切的基础),Context(上下文),SpEL(spring的表达式语言)
- AOP:面向切面编程
- 对数据访问的支持:jdbc,ORM(Mybatis等),Transaction(事务的管理),JMS(java邮件服务)
- Web:Spring MVC
2. IOC(Inversion of Control 控制反转)
下面用代码的形式看一下IOC的设计思想
创建对象由spring来创建,装配
DAO层:
public interface UserDao {
public void getUser();
}
DAO层的实现层:
我们现在有一个实现DAO层的类,是Mysql的
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取----Mysql");
}
}
Oracle的
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取----Mysql");
}
}
service的接口层,定义接口,通过DAO层取=数据
public interface UserService {
public void getUser();
}
service的实现层:
import dao.UserDao;
import daoimpl.UserDaoMysqlImpl;//可以去掉了
import service.UserService;
public class UserServiceImpl implements UserService {
//自己创建的对象,现在获取的是Mysql,后面如果我想要换成Oracle的时候就要改代码
//后面涉及到的代码越来越多的话,耦合性越来越大
//private UserDao userDao = new UserDaoMysqlImpl();
//进一步修改代码
private UserDao userDao = null;
//对外提供一个设置的方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
Test(相当于客户端)
public class Test {
public static void main(String[] args) {
//在这里创建对象
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
分析:
1.我们可以看一下private UserDao userDao = new UserDaoMysqlImpl();这条语句是我们手动new出来的,这时候我们可以通过userDao这个对象去调用对应的方法。这没问题,但是如果以后我要改成Oracle,后面涉及到的代码越来越多的话,耦合性越来越大。 这样我们要改的代码就会很多,这是不利于我们后面的代码维护的。
2.我们看进一步修改后的代码,我们对外提供一个接口setUserDao方法来设置userDao,这样看起来是不是不管我们以后要改成什么Oracle还是Mysql,只要是实现Dao方法的传进来一个对象可以了。
3.我们再观察Test类,Test类就相当于客户端,UserServiceImpl就相当于应用程序了,应用程序不用再自己new对象,完全是将new对象的这个步骤交给了Test类(客户端),在由必要的时候才在客户端new一个对象。现在看起来还是我们手动的,但是如果我们将这些交给配置文件,我们就省了这一步功夫了。
通过上面的例子,我们可以得出IOC的好处:
- 对象原来是程序本身创建的,变成了程序接收对象;
- 我们在开发的时候可以更加地注重业务的开发
- 实现了service和dao层的解耦工作,没有直接的依赖关系(举个简单的例子,我们可以把包含UserDaoMysqlImpl这个类的包名去掉了)
3.SpringIOC实现
我们在http://repo.springsource.org/libs-release-local/org/springframework/spring中下载对应的jar包
这里插入一个知识点:
IOC和DI(依赖注入,Dependency Injection)的区别
1.IOC:是把对象的创建交给Spring管理,由SpringIOC容器来创建对象,管理依赖关系
2.DI:依赖注入,在创建对象的过程中,向类里面的属性设置值
3.IOC和DI关系:依赖注入不能单独存在,必须在控制反转的基础上完成,就是注入类里面的属性值,不能直接注入,必须创建类的对象再完成注入
1.导入相关的jar包
image.png2.创建配置文件和相关的实体类
public class Hello {
private String name;
public void setName(String name) {
this.name = name;
}
}
ApplicationContext.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id = "hello" class="com.spring.test.Hello">
<property name="name" value="Spring的使用者"></property>
</bean>
</beans>
创建一个测试类
package test;
import com.spring.test.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBean {
public static void main(String[] args) {
//加载spring的配置文件,将配置文件中的对象进行创建
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//根据配置文件的id获得Hello对象
Hello hello = (Hello)applicationContext.getBean("hello");
hello.show();
}
}
结果:
image.png
4.Spring的bean管理
上面我们已经看到了基本的实现,下面我们来详细介绍一下bean的管理,有两种方式
- 使用配置文件方式实现(如上文)
- 使用注解的方式
Spring实例化bean的三种方式:
1.通过无参构造方法
2.通过有参构造方法
3.通过工厂模式:
- 工厂静态
- 工厂非静态
上文已经展示了无参构造方法了,下面重点介绍剩下的两种
通过有参构造方法
首先我们看看实体类(必须有带参数的构造方法)
public class User {
private int id;
private String name;
public User(int id,String name) {
this.id = id;
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
bean配置
<bean id = "user" class="com.spring.test.User">
<constructor-arg index="0" name = "id" value="1"></constructor-arg>
<constructor-arg index="1" name = "name" value="大帅比"></constructor-arg>
</bean>
测试类:
public class TestBean {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
User user = (User)applicationContext.getBean("user");
System.out.println(user.getId() + " " + user.getName());
}
}
image.png
PS:
在constructor如果构造函数的值是一个对象,而不是一个普通的类型的值,我们就需要用到ref属性,而不是value属性
比如说
我在User对象上维护了Address对象的值,想要在构造函数中初始化
<bean id = "address" class="Address"></bean>
bean id = "user" class="com.spring.test.User">
<constructor-arg index="0" name = "id" value="1"></constructor-arg>
<constructor-arg index="1" name = "address" ref = "address"></constructor-arg>
</bean>
工厂静态方法
写一个Factory
public class Factory {
public static User getBean() {
return new User();
}
}
<bean id = "user" class="com.spring.test.Factory" factory-method="getBean"></bean>
image.png
工厂非静态方法
public class Factory {
public User getBean() {
return new User();
}
}
<bean id="factory" class="com.spring.test.Factory"></bean>
<bean id = "user" factory-bean="factory" factory-method="getBean"></bean>
装载集合(setter注入,要有set方法)
如果对象上的属性或者构造函数具有集合的时候,我们又要为其赋值,可以通过以下赋值:
在构造函数中
<bean id = "user" class="com.spring.test.User">
<constructor-arg>
<list>
//基本类型
<value></value>
</list>
</constructor-arg>
</bean>
在属性上
<bean id = "user" class="com.spring.test.User">
<property name="name">
<list>
//引用类型
<ref></ref>
</list>
</property>
</bean>
5.Spring配置文件中bean标签中的属性讲解
- id:唯一的标志,只能唯一
- class属性:要创建的对象的全路径
- scope:bean的作用范围
1.singleton:创建的对象是单例的,也是scope属性的默认值
2.prototype:创建的对象是多例的
3.globalSession:用在单点登录上即(SSO,single sign on)
6.注解的方式使用bean
上面我们可以的看到,如果我们的Bean不断增加的话,bean配置会越来越多,自己也会越来越乱,这个时候我们推荐使用注解的方式来优化我们的编码过程
1.引入context命名空间
xmlns:context="http://www.springframework.org/schema/context"
2.开启注解扫描器
<context-:component-scan base-package="com.spring"></context-:component-scan>
3使用Repository注解
//把对象添加到容器中,首字母会小写
@Repository("userDao")
public class UserDaoMysqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取----Mysql");
}
}
4.使用Service注解
//把UserService对象添加到IOC容器中,首字母会小写
@Service("userService")
public class UserServiceImpl implements UserService {
//如果@Resource不指定值,那么就根据类型来找--->UserDao....当然了,IOC容器不能有两个UserDao类型的对象
//@Resource
//如果指定了值,那么Spring就在IOC容器找有没有id为userDao的对象。
@Resource(name = "userDao")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
5.使用Controller注解
@Controller
public class Test {
@Resource(name = "userService")
private UserService userService;
public static void main(String[] args) {
//在这里创建对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.getUser();
}
}
常用注解:
-
@ComponentScan扫描器
-
@Configuration表明该类是配置类
-
@Component 指定把一个对象加入IOC容器--->@Name也可以实现相同的效果【一般少用】
-
@Repository 作用同@Component; 在持久层使用
-
@Service 作用同@Component; 在业务逻辑层使用
-
@Controller 作用同@Component; 在控制层使用
-
@Resource 依赖关系
如果@Resource不指定值,那么就根据类型来找,相同的类型在IOC容器中不能有两个
如果@Resource指定了值,那么就根据名字来找
网友评论