Spring框架学习笔记

1. Spring

Spring的核心要素有两点,ioc(Inversion of Control)aop(Aspect Oriented Programmin),即控制反转面向切面编程

1.1 控制反转(IOC)

Spring框架能够提供对程序中对象的创建、赋值和管理,而不需要我们手动去创建对象,IOC的底层采用的是反射机制,Servlet就是一种IOC的体现,在Servlet程序中,我们并没有创建过Servlet对象,而全部都是由Tomcat服务器提供对Servlet的创建、管理和销毁等操作,我们只需要专注于业务逻辑的实现,简化开发流程。

开发流程

  1. 配置pom.xml文件,加入spring框架各个组件的坐标
  2. 编写spring配置文件applicationContext.xml,放置于resources目录中
  3. 在spring配置文件中加入各个组件bean
  4. 实现文件中可以对直接对bean进行调用

示例
spring.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" 
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!--在spring配置文件中配置所需要的bean-->
	<!--
		id是所需要的类对象的唯一标识
		class代表id所对应的类的全限定类名
	-->
	<bean id="userDao" class="com.xxx.xxx.UserDaoImpl"></bean>

这样配置之后就可以使用该类的实例对象,使用方法为:

public static void main(String[] args){
	// 通过spring的核心配置文件来加载其中定义的bean
	ApplicationContext app = new ClassPathXmlApplicationContext('applicationContext');
	// 以id为参数来获取对应的类对象
	UserDao userDao = (UserDao)app.getBean('userDao');
	// 可以调用userDao的方法
	//...
}

在Spring中,框架采用反射机制,默认使用bean的无参构造方法来创建实例,在配置bean时,可以指定bean的作用范围,通常有singletonprototype两种方式,方式的写法如下:

<bean id="userDao" class="com.xxx.xxx.UserDaoImpl" scope="singleton"></bean>

这两种方法的区别如下表,Spring默认创建是singleton

参数作用作用范围
singleton框架中只包含一个实例在读取主配置文件时就创建对象
prototype框架中可以包含多个实例调用一次getBean方法就创建一个新对象

在创建Bean实例时,可以指定方法来指定bean进行初始化init或者销毁时的动作

<bean id="userDao" class="com.xxx.xxx.UserDaoImpl" init-method="init" destory-method="destory"></bean>

同时需要在userDao的类中添加对应名称的方法

public class UserDaoImpl {
	public void init(){
		// do some...
	}
	public void destory(){
		// do some...
	}
}

最后,Bean的实例化方式除了无参构造方法以外,还有两种方法

  1. 工厂静态方法实例化
  2. 工厂实例方法实例化

在这两种方法中,需要实现bean的工厂类,并在工厂中定义实例创建的方法,同时需要在Spring的配置文件applicationContext.xml文件中添加工厂的bean,并在其中添加属性factory-method,采用工厂中的方法来构造实例

如果是静态工厂方法,那么只需要实现一个工厂类,调用其中的静态方法;但如果是工厂实例方法,那么需要先生成一个工厂的bean,再在其中调用工厂中的方法。

1.2 依赖注入(DI)

1.2.1 引用类型依赖注入

想在某个类,比如UserService类中注入UserDao类的对象(UserService类中有UserDao类的实例),有以下几种方法(在框架的层面实现注入而不需要进入到代码中):

1)set方法注入
<bean id="userDao" class="com.xxx.xxx.UserDaoImpl"></bean>
<bean id="userService" class="com.xxx.xxx.UserServiceImpl">
	<!--
	第一个name是UserService类中setUserDao()方法的set后面的名称
	第二个ref属性代表这个引用了上方id为userDao的bean来进行注入
	-->
	<property name="userDao" ref="userDao"></property>
</bean>
2)有参构造器注入

这个方法需要在UserService类中提供一个有参构造方法

public class UserService{
	private UserDao userDao;
	// constructor
	public UserService(UserDao userDao){
		this.userDao = userDao;
	}
	// other method...
}

然后配置主配置文件

<bean id="userDao" class="com.xxx.xxx.UserDaoImpl"></bean>
<bean id="userService" class="com.xxx.xxx.UserServiceImpl">
	<!--
	第一个name是UserService类中构造方法的参数名
	第二个ref属性代表这个引用了上方id为userDao的bean来进行注入
	-->
	<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

1.2.2 普通数据类型依赖注入

public class UserService{
	private String userName;
	private int age;
	// getter and setter method...
}
<bean id="userService" class="com.xxx.xxx.UserServiceImpl">
	<property name="userName" value="zhangsan"></property>
	<property name="age" value="18"></property>
</bean>

1.2.3 集合类型依赖注入

public class UserService{
	private List<String> strLists;
	private Map<String, User> userMap;
	// getter and setter method...
}
public class User{
	private String userName;
	private int age;
	// getter and setter method...
}
<!--user对象,用于依赖注入到map的value中-->
<bean id="userOne" class="com.xxx.xxx.User">
	<property name="userName" value="zhangsan"></property>
	<property name="age" value="18"></property>
</bean>

<bean id="userTwo" class="com.xxx.xxx.User">
	<property name="userName" value="lisi"></property>
	<property name="age" value="28"></property>
</bean>

<bean id="userService" class="com.xxx.xxx.UserServiceImpl">
	<property name="strLists">
		<list>
			<value>aaa</value>
			<value>bbb</value>
			<value>ccc</value>
		</list>
	</property>
	<property name="userMap">
		<map>
			<entry key="userone" value-ref="userOne"></entry>
			<entry key="usertwo" value-ref="userTwo"></entry>
		</map>
	</property>
</bean>

1.2.4 配置数据库连接池

采用alibaba的Druid数据库连接池,在spring的主配置文件中配置如下,同时还需要在pom.xml文件中引入各个依赖项的坐标

	<!--加载外部的properties文件-->
	<context:property-placeholder location="classpath:jdbc.properties"/>

	<!--数据库连接池配置 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        destroy-method="close" lazy-init="false">
        <!--以下是各项配置参数的设置-->
        <!--属性可以在jdbc.properties配置文件中读取-->
        <!--property后面的name是setter方法的set后面的那个属性名-->
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="initialSize" value="1" />
        <property name="maxActive" value="50" />
        <property name="maxWait" value="30000" />
 
        <property name="filters" value="stat,wall" />
        <property name="timeBetweenEvictionRunsMillis" value="3000" />
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="validationQuery" value="SELECT 'x'" />
    </bean>    

1.3 注解(Annotation)

使用注解可以大大减少配置xml文件的工作,简化开发流程

1.3.1 原始注解

注解说明
@Component在类上标注用于实例化Bean
@Controller使用在web项目中的controller层类上实例化Bean
@Service使用在web项目中的service层类上实例化Bean
@Repository使用在web项目中的dao层类上实例化Bean
@Autowired使用在字段上用于类型注入(Spring会根据字段类型去寻找对应的bean注入)
@Qulifier配合@Autowired一起使用,使得@Autowired可以根据名称进行注入,一般写为@Qulifier("xxx")
@Resource相当于@Qulifier+@Autowired,依照名称进行注入
@Value对普通类型注入属性,通常用于配置文件的读取注入参数@Value(${xxx})
@Scope标注Bean的作用范围,一般用在类上,常用@Scope("singleton")或者@Scope("prototype")
@PostConstruct使用在方法上标注该方法是Bean的初始化方法,通常用于init()方法
@PreDestory使用在方法上标注该方法是Bean的销毁方法

下面的几个类给出了一些常用的方式

// 业务逻辑层,根据请求实现特定的逻辑
@Service
public class MusicServiceImpl implements MusicService {
    @Autowired
    private MusicDao musicDao;

    @Override
    public int addMusic(Music music) {
        int result = musicDao.insertMusic(music);
        return result;
    }

    @Override
    public List<Music> findMusics() {
        return musicDao.selectMusics();
    }
}

// web层,处理请求,调用相应的service
@Controller
public class MusicController {
    @Resource
    private MusicService musicService;

    // 添加音乐
    @RequestMapping("/addMusic.do")
    public ModelAndView addMusic(Music music){
        ModelAndView mv = new ModelAndView();
        String tips = "注册失败";
        // 调用service处理添加音乐
        int res = musicService.addMusic(music);
        if(res > 0){
            tips = "音乐【" + music.getName() + "】添加成功";
        }
        // 结果页面
        mv.addObject("tips", tips);
        // 指定结果页面
        mv.setViewName("result");
        return mv;
    }
}

但是使用上面的这些注解,只能够注解我们自定义的一些类,对于一些不是我们自定义的第三方类,就束手无策了,例如alibaba的druid数据库连接池,如果使用上面的注解方式,就必须找到druid连接池的源码并在上面进行注解,这显然不现实,那么为了完全替代xml配置文件,需要使用到一些新的注解。

1.3.2 新注解

注解说明
@Configuration用于指定当前类是一个Spring核心配置类,当创建容器时会从该类上进行注解的加载
@ComponentScan用于指定Spring在初始化容器时需要扫描的包
@Bean用在方法上,将方法的返回值存储到Spring容器中
@PropertySource用于加载.properties配置文件中的信息
@Import用于导入其他的配置类

示例代码

// 核心配置类

// 标志该类是Spring的核心配置类
@Configuration
// 组件扫描器,扫描参数所对应的包
@ComponentScan("com.xxx.xxx")
// 加载数据库连接池的配置
@Import({DataSourceConfiguration.class, xxx.class})
public class SpringConfiguration{
}
// 数据库连接池配置

@PropertySource("classpath:xxx") // 读取配置文件
public class DataSourceConfiguration{
@Value("${jdbc.driver}") // 读取配置文件中的信息,解耦合
	private String driverClass;
	// 其余配置文件信息...

	@Bean("xxx") // 参数为对象在容器中的名称,Spring会将当前方法的返回值以xxx的名称存储在容器中
	public DataSource getDataSource(){
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setDriverClass(driverClass);
		// 其余设置项...
		
		return dataSource;
	}
}

那么在main函数中的写法变为了

public static void main(String[] args){
	ApplicationContext app = new AnnotationConfigurationContext(SpringConfiguration.class);
	xxx cls = app.getBean(xxx.class);
	cls.method();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值