Spring工厂
1、方便解耦,简化开发,IOC控制反转
Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护交给Spring
2、AOP 编程的支持
Spring 提供面向切编程,可以方便的实现对序进行权限拦截、运监控等功能
3、声明式事务的支持(张三给李四转账,要么同时成功,要么同时失败)
只需要通过配置就可以完成对事务的管理,而无手动编程
4、方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,其内部提供了对各种优优秀框架的支持(如Struts,Mybatis,Hibernate)。
IOC:Spring就是一个大的内存容器(一块内存区域),三层架构里面上一层不需要再去new下一层对象,在上一层只需要写下一层的接口,new对象由Spring容器帮我们完成,各层直接向Spring容器要对象就可以。
Spring框架
控制反转(Inversion on Control)IOC
对象的创建交给外部容器来完成(这里就是交给Spring容器),这就叫控制反转。
需要什么,就去创建什么(自己去new),这就叫“控制正转”(通俗一点就是自己控制new哪个对象)。
依赖注入:Dependency injection (DI)
现在new这个对象不是由自己new,是由Spring容器帮我们new对象,现在要得到这个Spring容器new出来的对象,==就要“依赖”Spring容器,“注入”Spring容器new出来的对象。 ==
class StudentController{
// 对象的创建交给别人去new(现在交给Spring容器new StudentServiceImpl(),new出来对方放在Spring容器),这就叫控制反转“IOC”
private IStudentService studentService;
// 将Spring容器中new出来的对象通过set方法赋值给studentService,这个过程叫依赖注入:DI
public void setStudentService(IStudentService studentService) {
this.studentService = studentService;
}
}
IOC和DI区别:
IOC:解决对象创建的问题(对象的创建交给别人)Inversion of Control。
DI:在创建完对象后,对象关系的处理就是依赖注入(通过set方法实现依赖注入)Dependency injection。
先有IOC(对象创建),再有DI(处理对象关系)
在三层架构中最终实现的效果是:在Controller不会出现Service层具体的实现类代码,只会看到Service层接口,
Service层也不会出现Dao层具体实现类的代码,也只会看到Dao层的接口。
开发
bean
bean就是生成一个实例对象意思
<!-- bean标签会帮助我们去new一个指定类的对象,然后将new出来的对象放到spring容器
这个对象的名字就是name="student",后面想从Spring容器中拿出来时候就根据这个name的值 -->
<bean name="student" class="com.situ.spring.entity.Student"/>
从IOC容器中取出bean
public void test1() {
// 创建Spring容器,在xml中配置的bean都会new出对象放到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从Spring容器中根据名字取出指定的new出来的对象
Student student = (Student) context.getBean("student");
System.out.println(student);
}
每次容器启动的时候会创建容器(applicationContext.xml)中配置的所有的bean对象。
并不是从容器中拿出这个bean的时候才去实例化
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//Student student = (Student) context.getBean("student");
//System.out.println(student);
}
Bean的属性
scope:范围
scope值:
1、singleton是scope的默认值,单例模式,在Spring容器中只存在一个实例。
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student1 = (Student) context.getBean("student");
Student student2 = (Student) context.getBean("student");
System.out.println(student1 == student2);//
}
true
2、prototype:多例,会创建多个对象
<bean scope="prototype" name="student" class="spring.entity.Student"/>
public void test3() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student1 = (Student) context.getBean("student");
Student student2 = (Student) context.getBean("student");
System.out.println(student1 == student2);//
}
false
Spring属性注入
1、set方法注入
<bean name="banji" class="spring.entity.Banji">
<property name="id" value="1"/>
<property name="name" value="Java2012"/>
</bean>
<bean name="student" class="spring.entity.Student">
<!-- 值类型注入 -->
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="23"/>
<property name="gender" value="男"/>
<!-- ref:reference参考、引用
引用类型的注入
-->
<property name="banji" ref="banji"/>
</bean>
2、构造方法注入
argument:参数
parameter:参数
<bean name="banji" class="spring.entity.Banji">
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="Java1912"/>
</bean>
<bean name="student" class="spring.entity.Student">
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="李四"/>
<constructor-arg name="age" value="23"/>
<constructor-arg name="gender" value="男"/>
<constructor-arg name="banji" ref="banji"/>
</bean>
三层架构
三层架构使用Spring来管理,达到一个目的:在上层只看到下一层的接口就可以,不需要出现具体的实现类。
<bean name="studentController" class="spring.controller.StudentController">
<property name="studentService" ref="studentService"/>
</bean>
<bean name="studentService" class="spring.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"/>
</bean>
<bean name="studentDao" class="spring.dao.impl.StudentDaoImpl"/>
但是如果我有很多属性的话需要一个一个写很麻烦,所以可以使用注解。
注解开发方式
这个一定要加!
<!--base-package:是要扫描的包,扫描这个包下面类上带有注解@Controller @Service @Repositioy -->
<context:component-scan base-package="spring"/>
<bean name="courseController" class="spring.controller.CourseController">
</bean>
@Controller 这个注解相当于在applicationContext.xml中写的上面的bean,
默认的名字是类名的首个单词小写courseController
@Controller("courseController")
public class CourseController {
// <property name="courseService" ref="courseService"/>
// @Resource:从Spring容器中根据名字拿出指定的对象注入进来
@Resource(name = "courseService")
private ICourseService courseService;
public void selectAll() {
System.out.println("CourseController.selectAll()");
List<Course> list = courseService.selectAll();
}
}
这样方便了很多,但是因为写注解的时候没有提示很容易写错,而写错就会编译错误,所以可以只用自动装配。
Autowired 自动装配
@Resource默认是按照名称装配的
byName 通过参数名自动装配,如果一个bean的name 和另外一个bean的 property 相同,就自动装配。
@Autowired是默认按照类型装配的
byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另外一个bean的property属性的数据类型兼容,就自动装配。
如果有多个子类情况下:
情况一:
IBanjiService BanjiServiceImpl BanjiServiceImpl2
IBanjiService banjiService;
会报错:
expected single matching bean but found 2: banjiServiceImpl,banjiServiceImpl2
因为在容器中子类对象有两个,而且变量的名字是banjiService和任何一个容器中对象的名字都不一致,所以找不到(只有一个子类对象情况下变量名可以随便写)。
也同时证明,@Controller、@Service、@Repository不起名字,默认的名字是类的名字首字母变小写。
情况二:
IBanjiService banjiServiceImpl2;
不会报错,这时候虽然有多个但是有限根据变量名去容器中找相同变量名的对象,所以注入过来的是new BanjiServiceImpl2()的对象。
情况三:还是希望写成
IBanjiService banjiService;
// @Resource(name = "banjiService")
@Autowired
@Qualifier(value = "banjiServiceImpl2")
private IBanjiService banjiService;
@Controller
public class StudentController {
// <property name="studentService" ref="studentService"/>
// @Resource(name = "studentService")
@Autowired
private IStudentService studentService;
}
//@Service("studentService")
@Service
public class StudentServiceImpl implements IStudentService{
// @Resource(name = "studentDao")
@Autowired
private IStudentDao studentDao;
}
//@Repository("studentDao")
@Repository
public class StudentDaoImpl implements IStudentDao{
}