Spring入门学习

1、spring是什么?

spring是一个轻量的java开源框架,它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。其核心功能是控制反转(ioc)和面向切面编程(aop)。

2、spring的优点

  • 非侵入式设计
  • 方便解耦,简化开发
  • 支持AOP
  • 支持声明式事务处理
  • 方便程序测试
  • 方便集成各种优秀框架
  • 降低java ee api的使用难度

3、spring框架的结构体系

4、spring的下载,包含两部分spring框架包和第三方依赖包

spring下载地址,下载后直接解压

4个核心模块

  1. spring-core:包含spring的核心工具类,spring其它模块都要用到这个包的类
  2. spring-beans:所有应用都要用到的JAR包,包含访问配置文件,创建和管理beans以及进行控制反转和依赖注入的类
  3. spring-context:提供了在基础IoC功能上的拓展服务,还提供了许多企业级服务的支持
  4. spring-expression:定义了spring的表达式语言

第三方依赖:commons.logging的jar包

下载地址

IOC环境搭建

程序的耦合:调用者与被调用者的依赖关系

我们应该尽量做到编译时不依赖,运行时才依赖,ioc就是用来进行解耦的,而且它的作用只是用来解耦。

需要的包:4+1,4个核心包 + commons.logging

配置文件:

  • 位置:任意,一般放在类路径,即src下面
  • 名称:任意,个人习惯(bean.xml)
  • 约束:spring-framework-4.3.13.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
<?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="userServiceId" class="com.lcz.service.impl.UserServiceImpl"></bean>

</beans>

使用

package com.lcz.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.lcz.service.UserService;
public class UserController {
	public static void main(String[] args) {
		String xmlPath = "bean.xml";
		//获取容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		//通过bean的id获取实例对象
		UserService us = (UserService) applicationContext.getBean("userServiceId");
		us.addUser();
	}
}

bean的两种创建规则

  • BeanFactory:提供的是一种延迟创建bean对象的思想方式,什么时候用什么时候创建
  • ApplicationContext:提供的是一种立即创建bean对象的思想方式,xml文件解析完立即创建

bean的三种创建方式

  • 调用默认无参构造器:默认情况下,如果类中没有默认无参构造器,则创建失败,抛出异常
  • 使用静态工厂方式:使用静态工厂中的方法创建对象,需要使用bean标签中的factory-method属性指定静态工厂中创建对象的方法
 <!-- 配置静态工厂方法 -->
    <bean id="staticFactory" class="com.lcz.service.Factory" factory-method="getUserServiceImpl"></bean>
  • 使用实例工厂中方式:

bean的作用范围:可以通过配置的方式来调整作用范围

配置的属性:bean标签的scope属性

属性的取值:

  • singleton:单例的(默认值)
  • prototype:多例的(当我们让spring接管struts2的action时,必须配置此值)
  • request:作用范围是一次请求和当前请求的转发
  • session:作用范围是一次会话
  • globalsession:作用范围是一次全局会话(服务器集群时,全局session)

bean的生命周期

两个个属性:init-method,destroy-method,分别在对象创建和销毁时被调用的方法

<bean id="userServiceId" init-method="init" destroy-method="destroy" class="com.lcz.service.impl.UserServiceImpl"></bean>
public class UserServiceImpl implements UserService {

	@Override
	public void addUser() {
		System.out.println("添加成功");
	}
	
	public void init() {
		System.out.println("对象创建");
	}
	
	public void destroy() {
		System.out.println("对象被销毁");
	}
}

1、单例模式

  • 创建:容器已创建,对象就被创建
  • 存在:容器存在,对象就存在
  • 销毁:容器销毁,对象就被销毁

2、多例模式

  • 创建:每次使用时都创建一个对象
  • 存在:对象在使用中则一直存在
  • 销毁:当对象长时间没使用,并且没别别的对象引用,则由java的垃圾回收器销毁

DI依赖注入

注入的方式,三种:

  1. 构造函数注入
  2. set方法注入
  3. 注解注入

注入的数据类型

  1. 基本类型和String类型
  2. bean类型(必须是在spring配置文件中出现过的bean)
  3. 其它复杂类型(集合类型)

构造函数注入

标签:constructor-arg

标签的属性:上面三个是指定给哪个参数赋值,下面两个是指定参数赋什么值

  • type:指定参数的类型
  • index:指定参数的索引位置,0开始
  • name:指定参数的名称(一般使用这个)
  • value:指定基本数据类型或者string数据类型的值
  • ref:指定其它bean类型的数据

标签的位置:写在bean标签的内部


    <!-- 配置bean -->
    <!-- 使用构造函数配置属性 -->
    <bean id="userServiceId"  class="com.lcz.service.impl.UserServiceImpl">
    	<constructor-arg name="name" value="张三"></constructor-arg>
    	<constructor-arg name="age" value="25"></constructor-arg>
    	<constructor-arg name="today" ref="date"></constructor-arg>
    </bean>
    
    <!-- today属性需要用到 -->
    <bean id="date" class="java.util.Date"></bean>
public class UserServiceImpl implements UserService {
	private String name;
	private Integer age;
	private Date today;
	
	 public UserServiceImpl(String name,int age,Date today) {
		 this.name = name;
		 this.age = age;
		 this.today = today;
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public void addUser() {
		System.out.println("添加成功");
	}
	
	public void print() {
		System.out.println(this.name+this.age+this.today);
	}
}

setter方法注入

标签:property

属性:同构造函数注入一样

位置:bean标签内部

    <bean id="userServiceId"  class="com.lcz.service.impl.UserServiceImpl">
    	<property name="name" value="李四"></property>
    	<property name="age" value="27"></property>
    	<property name="today" ref="date"></property>
    </bean>
    
    <!-- today属性需要用到 -->
    <bean id="date" class="java.util.Date"></bean>
public class UserServiceImpl implements UserService {
	private String name;
	public void setName(String name) {
		this.name = name;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public void setToday(Date today) {
		this.today = today;
	}

	private Integer age;
	private Date today;
	
	
	@Override
	public void addUser() {
		System.out.println("添加成功");
	}
	
	public void print() {
		System.out.println(this.name+this.age+this.today);
	}
}

复杂类型注入

结构相同,标签可以互换。array,list,set可以互换map,props可以互换

    <!-- 复杂类型注入配置 -->
    <bean id="userServiceId"  class="com.lcz.service.impl.UserServiceImpl">
    	<property name="strings" >
    		<array>
    			<value>asd</value>
    			<value>qwe</value>
    			<value>asd</value>
    		</array>
    	</property>
    	<property name="list">
    		<list>
    			<value>asd</value>
    			<value>qwe</value>
    			<value>asd</value>
    		</list>
    	</property>
    	<property name="set">
    		<set>
    			<value>asd</value>
    			<value>qwe</value>
    			<value>asd</value>
    		</set>
    	</property>
    	<property name="map">
    		<map>
    			<entry key="a" value="AAA"></entry>
    			<entry key="b" value="BBB"></entry>
    		</map>
    	</property>
    	<property name="prop">
    		<props>
    			<prop key="A">AAA</prop>
    			<prop key="B">BBB</prop>
    		</props>
    	</property>
    	
    </bean>

基于注解的IOC

需要用的包:4 + 1 +   spring-aop包

约束:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

   <!-- 告知spring在创建容器是要扫描的包,当配置了此标签后,spring在创建容器后就回去指定的包及子包下去找对应的注解
   		标签是在一个context的名称空间里,所以必须先导入context名称空间
    -->
    <context:component-scan base-package="com.lcz"></context:component-scan>

</beans>

注解分类(复杂类型不能注入List  Set Map等)

1、用户创建bean对象

 @Component

作用:相当配置了一个bean标签

位置:出现在类上

属性:value。含义是指定bean的id,当不写时默认为当前类的短命,首字母改小写

由此注解衍生的三个注解,与@Component的使用和属性一模一样

① @Controller  一般用于controller层

② @Service     一般用于service层

③ @Repository  一般用于持久层

2、用于注入数据的

@Autowired

作用:自动按照类型注入,只要有唯一的类型匹配就能注入成功,使用注解注入set方法不是必须的。所谓的唯一类型,举个例子,当dao层有一个实体类继承了UserDao接口,我们在service中使用注解,来使用UserDao属性,spring默认找它的实现类,如果唯一,则注入成功,如果不唯一,则有多个类实现UserDao接口,否则将变量名作为bean的id来查找。

@Qualifier

作用:在自动按照类型注入的基础上,再按照bean的id注入

属性:value,用于指定bean的id

注意:在给类成员注入数据时,不能独立使用,必须配合@Autowired,在给方法的形参注入数据时可以独立使用。

@Resource

作用:按照bean的id注入

属性:name,用于指定bean的id

示例:@Resource(name="userDao")

@Value

作用:用于注入基本类型和String类型的数据

属性:value,用于指定基本类型和String类型的值,还可以借助spring中的el表达式读取properties配置文件中的数据

示例:@Value("23")

3、用于改变作用范围的

@Scope

作用:用于改变bean的作用范围

属性:value,取值与xml配置里的scope属性一样

4、和生命周期相关的

@PostConstruct:用于绑定初始化方法

@PreDestroy:用于绑定销毁方法

5、其它注解

@Configuration

作用:将一个类作为配置类

@ComponentScan

作用:用于spring配置扫描包,可以完全脱离xml文件

位置:在类上

@Bean

作用:把方法的返回值注入spring容器

属性:name,用于指定bean的id,如果不指定,默认为方法名称

@Import

作用:导入其它配置类,使用@Import导入的配置类的实例不会进入spring容器

@PropertySource

作用:配置properties文件

使用配置类的案例

//主配置类
package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@ComponentScan({"com.lcz"})
@Import({Other.class})
@PropertySource("classpath:config/test.properties")
public class SpringConfiguration {
	
	//配置资源占位符解析器4.3.5及以上不用配
	@Bean
	public static PropertySourcesPlaceholderConfigurer pspc() {
		return new PropertySourcesPlaceholderConfigurer();
	}
}
//其它配置类
package config;

import java.util.Date;

import org.springframework.context.annotation.Bean;
public class Other {
	
	@Bean(name="today")
	public Date getToday() {
		return new Date();
	}
}
//使用
package com.lcz.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.lcz.service.impl.UserServiceImpl;

import config.SpringConfiguration;
public class UserController {
	
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		//获取容器
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
		//通过bean的id获取实例对象
		UserServiceImpl us = (UserServiceImpl) applicationContext.getBean("userService");
		us.addUser();
		
	}
}
package com.lcz.service.impl;

import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import com.lcz.dao.UserDao;
import com.lcz.service.UserService;

@Service("userService")
@Scope("singleton")
public class UserServiceImpl implements UserService {
	@Resource(name="userDao")
	private UserDao ud = null;
	
	//使用properties里的配置数据,使用el表达式
	@Value("${username}")
	private String name;
	
	@Value("23")
	private int age = 0;
	@Resource(name="today")
	private Date date;
	@Override
	public void addUser() {
		ud.addUser();
		System.out.println(name+age+date);
		System.out.println("添加客户service");
	}
	
	@PostConstruct
	public void init() {
		System.out.println("init....");
	}
	
}

@Qualifier的形参注入

package config;

import java.util.Date;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
public class Other {
	
	@Bean(name="today")
	public Date getToday(@Qualifier("date2")Date d) {
		return d;
	}
	@Bean(name="date1")
	public Date date1() {
		return new Date();
	}
	@Bean(name="date2")
	public Date date2() {
		return new Date();
	}
}

AOP:面向切面编程

意义:把我们程序中重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对我们的方法进行增强。

优势:减少重复代码、提高开发效率,方便维护

相关概念:

  • 连接点(Joinpoint):指那些被拦截到的点,在spring中,这些点是指方法,因为spring只支持方法类型的连接点。
  • 切入点(Pointcut):切入点是指我们要对哪些Joinpoint拦截的定义。
  • 通知/增强(Advice):通知是指拦截到Joinpoint后要做的事情。通知的类型:①前置通知②后置通知③异常通知④环绕哦通知⑤最终通知。
  • 引介(Introduction):引介是一种特殊的通知,在不修改类代码的前提下,引介可以在运行期为类动态的增加一些方法或属性。
  • 目标对象(Target):代理的目标对象。
  • 织入(Weaving):是指把增强应用到目标对象来创建新的代理对象的过程
  • 代理(Proxy):一个类被AOP织入增强后,就产生一个代理类
  • 切面(Aspect):是切入点和通知的结合

spring配置AOP(xml配置文件配置)

需要用到的包:4 + 1 + 2 + 2

4 + 1 为基础核心包,第一个2为spring-aop和spring-aspect两个包,第二个2为aspectjweaver和aopalliance两个三方依赖包

aspectjweaver下载地址     aoplliance下载地址

注意aspectjweaver最好1.8.2及以上

约束:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
       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
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

	<bean id="userService" class="com.lcz.service.impl.UserServiceImpl"></bean>
	    
    <!-- 配置AOP -->
    <!-- 第一步:把通知类交给spring来管理  -->
    <bean id="aopTest" class="com.lcz.controller.AOPTest"></bean>
    <!-- 导入aop名称空间,并使用aop:config进行配置  -->
    <aop:config>
    	<!-- 第三步,使用aop:aspect配置切面id属性用于给切面提供唯一标识,ref属性,用于引用应用通知bean的id -->
    	<aop:aspect id="test" ref="aopTest">
    		<!-- 第四步,配置通知类型 method属性,指定增强方法的名称 pointcut属性,用于指定切入点表达式-->
    		<!-- 
    			切入点表达式:execution(表达式)
    			表达式写法:访问修饰符 返回值 包名.包名...类名.方法名(参数列表)
    		 -->
    		<aop:before method="forward" pointcut="execution(public void com.lcz.service.impl.UserServiceImpl.addUser())" />
    	</aop:aspect>
    </aop:config>

</beans>

切入点表达式:

表达式:访问修饰符 返回值 包名.包名...类名.方法名(参数列表)

全匹配方式:public void com.lcz.service.impl.UserServiceImpl.addUser()

全通配方式:*  *..*.*(..)

注意事项:

  • 访问修饰符可以省略
  • 返回值可以写成通配符*,表示任意返回值
  • 包名可以使用通配符*,表示任意包,但是有几个包得写几个通配符,例如:*.*.*.*表示四个包
  • 包名可以使用..表示当前包及其子包,例如com..表示com包和其下面的子包
  • 类名和方法名都可以使用通配符*
  • 参数列表,可以使用具体类型。基本类型直接写类型(例如 int),引用类型必须写包名加类型(java.lang.Integer)
  • 参数类型可以使用通配符*,表示任意类型参数,但是必须有参数
  • 参数列表可以使用..表示有无参数均可,有参数,可以是任意类型

实际开发中,一般都是对业务层方法进行增强,* com.lcz.service.impl.*.*(..)

定义通用的切入点表达式:如果是写在了aop:aspect标签内部,则表示只有当前切面可用

<aop:aspect id="test" ref="aopTest">
    		<!-- 第四步,配置通知类型 method属性,指定增强方法的名称 pointcut属性,用于指定切入点表达式-->
    		<!-- 
    			切入点表达式:execution(表达式)
    			表达式写法:访问修饰符 返回值 包名.包名...类名.方法名(参数列表)
    		 -->
    		<aop:before method="forward" pointcut-ref="p1" />
    		<aop:after method="back" pointcut-ref="p1"/>
    		<aop:pointcut expression="execution(* com.lcz.service.impl.UserServiceImpl.*(..))" id="p1"/>
</aop:aspect>

如果切入点表达式写在了外面,即aop:config里,则所有切入面都可以使用,但是aop:pointcut必须写在aop:aspect前面

常用通知类型

1、aop:before,前置通知,永远在切入点方法执行之前执行

2、aop:after-returning,后置通知,切入点方法正常执行后执行

3、aop:after-throwing,后置通知,切入点方法异常时执行

4、aop:after,最终通知,切入点执行后,无论是否异常都会执行

5、aop:around,环绕通知

由动态代理可知,环绕通知指的是invoke方法,并且里面有明确的切入点方法调用。spring为我们提供了一个接口:ProceedingJoinPoint,该接口可以作为环绕通知的方法参数来调用。该接口中有一个方法proceed(),它的作用就等于method.invoke(),就是明确调用业务层方法(切入点方法)

public Object  around(ProceedingJoinPoint pjp) {
	Object ret = null;
	try {
		ret = pjp.proceed();
	} catch (Throwable e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally {
		
	}
	return ret;
}

环绕通知是spring给我们提供的手动指定通知位置的方法

使用注解配置AOP

约束:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">

	<context:component-scan base-package="com.lcz"></context:component-scan>
	 
	 <!-- 开启spring对注解aop的支持 -->   
    <aop:aspectj-autoproxy />

</beans>

注解配置案例

package com.lcz.utils;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component("logger")
@Aspect
public class Logger {
	
	@Pointcut("execution(* com.lcz.service.impl.*.*(..))")
	public void pt() {}
	
	@Before("pt()")
	public void beforeRun() {
		System.out.println("前置通知");
	}
}

使用纯注解,配置类配置

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

@Configuration
@ComponentScan({"com.lcz"})
@Import({Other.class})
@PropertySource("classpath:config/test.properties")
@EnableAspectJAutoProxy
public class SpringConfiguration {
	
	//配置资源占位符解析器4.3.5及以上不用配
	@Bean
	public static PropertySourcesPlaceholderConfigurer pspc() {
		return new PropertySourcesPlaceholderConfigurer();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值