1、首先我们来看一下什么是工厂模式?
把类对象的创建,交给工厂去完成,每个创建出来的实例,都是一个新的对象,主要的意义,就是把类对象的创建和应用解耦
工厂模式代码模拟
public class Test {
public static void main(String[] args) {
TV t1=TVFactory.creatTV();
TV t2=TVFactory.creatTV();
t1.play();
t2.play();
}
}
//声明一个类,叫工厂类,每次创建对象的时候让他帮我们创建
class TVFactory{
static TV creatTV() {
return new TV(5,6,"灰色",220);
}
}
//构造一个电视机类
class TV{
private int width;
private int height;
private String color;
private int v;
//构造方法
public TV(int width,int heigth,String color,int v){
this.color=color;
this.height=heigth;
this.width=width;
this.v=v;
}
void play() {
System.out.println("电视打开");
System.out.println("面积:"+height*width);
System.out.println("电压:"+v);
System.out.println("颜色:"+color);
}
}
2、Spring简介
spring是一个开源的控制反转(Inversion of control)IOC的面向切面(AOP)的容器框架,它主要的目的是简化企业开发
使用Spring的好处 :
1)可以降低组件之间的耦合度,实现软件各层直接的解耦
2)可以使用容器提供的众多服务,如:事物管理服务、消息服务等待,当我们使用容器管理事务时,开发人员就不再需要手工控制事务,也不需要处理复杂的事务传播
3)容器提供单例模式支持,开发人员不再需要自己编写实现代码
4)容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能
5)容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate
6)Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便 于应用的开发
Spring 负责管理容器中所有的组件, 这些组件统称为 Bean , 在Spring 的概念里,一切都是Bean其实Spring就是面向Bean的编程(BOP ,Bean Oriented Programming )
重要概念:
1)IOC(inversion ofcontrol)
应用本身不负责依赖对象的创建和维护,而是把它的创建的控制权交给外部容器去实现(比如Spring),叫控制反转
代码示例:
(1)由应用本身去创建,这种方式耦合度高
public class AdminServlet{
//admindao是AdminServlet的一个依赖对象
//本类中,admindao的创建是由应用本身来创建的
private AdminDao admindao=new AdminDao();
public void service(){
dao.login();
}
}
(2)那么怎么才能解决上面由这个应用不用自己创建要用的对象?而是只要声明就好?
方法:反转形式的,交给别人去创建,我们只需要用构造方法将需要用的对象由别人创建传 过来就行
只是模拟
反转形式的:admindao不由应用本身创建,由本人去创建
首先,这样我们能调用AdminDao的login方法吗?显然不行
public class AdminServlet{
private AdminDao admindao;//不用自己去创建,只要声明就行
public void service(){
admindao.login();
}
}
那怎么才不用创建,只要声明就可以使用它的方法呢?
public class AdminServlet{
private AdminDao admindao;
//来一个构造方法,将AdminDao的对象传过来,是不是就有了
此时,admindao的创建的控制权不在AdminServlet了,而是交给其他应用程序了
public AdminServlet(AdminDao admindao){
this.admindao=admindao;
}
public void service(){
admindao.login();
}
}
别人在使用的时候怎么弄呢?
1、由其他人去创建依赖对象,比如AdminDaoImpl()创建了AdminDao对象;
AdminDao admindao=new AdminDaoImpl();
2、注入依赖对象
AdminServlet servlet=new AdminServlet(admindao);
2)DI 依赖注入
为什么我们要用依赖注入呢?
主要是实现类之间的解耦,假如A类依赖B类,在实例化A类的话也要new一个B类,如果A的依赖的类换成C的话,所有实例化A的代码的new B都要替换掉,不利于代码维护。
如果使用Spring框架的DI,我们只需要修改xml文件中的一处就好。
同时不需要我们自己实例化对象,只需要从Spring的IoC容器中取出来用就好。
其实这种解耦就是把代码中的耦合转移到了xml文件中了。
在程序运行期,由外部容器动态的将依赖对象传给应用的进程
public AdminServlet{
//你只需要写这一句话,声明就行
private AdminDao admindao;
生成一个set方法,spring容器会在运行的时候,生成admindao的实例,并自动调用这个方法,把它的实例传过来
public void setDao(AdminDap admindao){
this.admindao=admindao;
}
然后我们就可以调用admindao的方法了
public void service(){
admindao.login();
}
}
3)AOP(Aspect Oriented Programing)面向切面编程
类似于过滤器
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
一、第一个spring程序
1)在lib包下导入包
2)在类路径下创建配置文件,名字一般叫application.xml 或者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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--新建之后写入这段代码,这段代码就是加载一个bean的配置-->
<bean id="xxx" class="com.beans.UserInfo">
<property name="id" value="11"/>
</bean>
</beans>
3)在src下创建com.beans的包,在里面建UserInfo.java文件
package com.beans;
public class UserInfo {
private int id;
private String userName;
private String password;
private String note;
@Override
public String toString() {
return "UserInfo [id=" + id + ", userName=" + userName + ", password=" + password + ", note=" + note + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
4)创建测试文件Test.java
public class Test {
public static void main(String[] args) {
//spring给我们提供的一个类,这个类能从类路径(src下或者你建的那个文件夹就是源文件夹也叫类路径下)下加载我们的spring的配置文件
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
//spring的配置文件已经加载进来了,然后现在我们就可以朝spring要一个对象了
UserInfo user=ioc.getBean("xxx",UserInfo.class);
System.out.println(user);
}
}
这个spring程序就建好了,现在我们看一下这三个文件的关系
1、项目结构
2、关系
二、四种实例化bean的方式(注入方式)
依赖对象的四种创建方式
为什么我们要将某些东西交给spring管理,像一些实体类,他没有什么实际的意义,所以直接交给spring管理没有多大意义,因为它又不需要解耦
spring一般管理哪些东西呢?
控制层,dao层啊,因为这些层之间有依赖关系,需要解耦
1)用set的方式注入
具体代码:
1、接口中
public interface UserDao {
void addUser();
void delUser();
void updateUser();
}
2)实现类中
public class UserDaoImpl implements UserDao{
public void addUser() {
System.out.println("addUser实现了");
}
public void delUser() {
System.out.println("delUser实现了");
}
public void updateUser() {
System.out.println("updateUser实现了");
}
}
3)控制层
public class UserServlet {
private UserDao userdao; //依赖对象
public void service() {
userdao.addUser();
userdao.delUser();
userdao.updateUser();
}
//要准备一个set方法,将来spring 容器会自动调用这个方法,把依赖对象传进来
public void setUserdao(UserDao userdao) {
this.userdao=userdao;
}
}
4)配置文件中
<?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 name="userDaoImpl" class="com.dao.UserDaoImpl"></bean>
<!-- 将servlet的实现 交给spring 管理 -->
<bean name="userServlet" class="com.servlet.UserServlet">
<property name="userdao" ref="userDaoImpl"> </property>
</bean>
</beans>
附: 也可以用内部bean的方式
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" >
<bean class="com.dao.UserDaoImpl" />
</property>
</bean>
5)测试类
public class Test {
public static void main(String[] args) {
//spring给我们提供的一个类,这个类能从类路径(src下或者你建的那个文件夹就是源文件夹也叫类路径下)下加载我们的spring的配置文件
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
//spring的配置文件已经加载进来了,然后现在我们就可以朝spring要一个对象了
UserInfo user=ioc.getBean("xxx",UserInfo.class);
//不用自己new,让ioc容器帮我们创建
UserServlet us=ioc.getBean("userServlet",UserServlet.class);
us.service();
System.out.println(us);
}
}
2)以构造函数的方式注入
1、UserServlet中
public class UserServlet {
//依赖对象
private UserDao userdao;
private UserInfo user;
private int age;
//用构造方法的形式注入,可以注入多个属性
//无参的构造方法
public UserServlet() {
// TODO Auto-generated constructor stub
}
//一个参数的
public UserServlet(UserDao userdao) {
this.userdao=userdao;
}
//三个参数的
public UserServlet(UserDao userdao,UserInfo user,int age) {
this.userdao=userdao;
this.user=user;
this.age=age;
}
public void service() {
userdao.addUser();
userdao.delUser();
userdao.updateUser();
System.out.println(user);
System.out.println(age);
}
}
2)配置文件中
<?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="xxx" class="com.beans.UserInfo">
<property name="id" value="11"/>
</bean>
<!-- 需要先将实现类加载进来 -->
<bean name="userDaoImpl" class="com.dao.UserDaoImpl"></bean>
<!-- 将servlet的实现 交给spring 管理 -->
<bean name="userServlet" class="com.servlet.UserServlet">
<constructor-arg name="userdao" ref="userDaoImpl"/>
<constructor-arg name="user" ref="xxx"/>
<constructor-arg name="age" value="22"/>
</bean>
</beans>
3)测试类
public class Test {
public static void main(String[] args) {
//spring给我们提供的一个类,这个类能从类路径(src下或者你建的那个文件夹就是源文件夹也叫类路径下)下加载我们的spring的配置文件
ClassPathXmlApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
//spring的配置文件已经加载进来了,然后现在我们就可以朝spring要一个对象了
UserInfo user=ioc.getBean("xxx",UserInfo.class);
//不用自己new,让ioc容器帮我们创建
UserServlet us=ioc.getBean("userServlet",UserServlet.class);
us.service();
System.out.println(us);
}
}
4)输出结果
3)用静态工厂注入
1、首先创建一个静态工厂的类
public class StaticFactory {
public static UserDao creatObject() {
return new UserDaoImpl();
}
}
2、在配置文件中配置
<bean name="userServlet" class="com.servlet.UserServlet">
<property name="userdao" ref="staticfactory"></property>
</bean>
<!--必须要指明要静态工厂中的那个方法-->
<bean name="staticfactory" class="com.dao.StaticFactory" factory-method="creatObject"></bean>
3、servlet中,还是需要写一个set方法帮我们注入
public class UserServlet {
//依赖对象
private UserDao userdao;
public void service() {
userdao.addUser();
userdao.delUser();
userdao.updateUser();
}
public void setUserdao(UserDao userdao) {
this.userdao=userdao;
}
}
4)用实例工厂的方法注入
就是静态工厂中的那个方法没有static关键字
1、实例工厂类
public class UserDaoFactory {
public IUserDao createUserDaoImplInstance() { //没有static 关键
return new UserDaoImpl();
}
}
2、配置文件
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" ref="userDaoImpl_name" />
</bean>
<bean name="userDaoFactory_name" class="com.dao.UserDaoFactory" />
<bean name="userDaoImpl_name" factory-bean="userDaoFactory_name" factory-method="createUserDaoImplInstance" />
那么我们现在知道了spring的作用,但是它到底为什么要这样做呢?
1、比如说有一天我们要将一个mysql的接口换成oracle的,传统的方式就是我们直接将代码里面的接口再new一次,但是有多少个servlet里面需要换呢?我们要改多少代码?而且假如说你这个项目交付了,那么是不是要重新生成字节码文件再次打包呢?这是不是很耗费呢?
因此,我们只声明,抽象化不具体,当我们要用那个的时候,然后在配置文件中配置这个bean,然后将它直接替换掉就行
解耦合:
public class UserServlet {
private IUserDao dao; //应用依赖于抽象,而不依赖于具体
public void setDao(IUserDao dao) {
this.dao=dao;
}
public void service() {
dao.addUser();
dao.updateUser();
dao.delUser();
}
}
配置文件中,可以配置多个实现,
<bean name="userServlet_name" class="com.servlet.UserServlet" >
<property name="dao" ref="userDaoImpl_name" />想实现那个直接换掉ref就行
</bean>
两种实现方式
<bean name="userDaoImpl_name" class="com.dao.UserDaoImpl" />
<bean name="userDaoImplOracle_name" class="com.dao.UserDaoImplOracle" />
可以在配置文件中,方便的随时切换具体使用哪一个实现