本篇博文主要包含:
- springIOC(控制反转)
- DI(依赖注入)
- AOP(切面编程)
-Spring的环境搭建 - spring作用域
-singleton:表示一个容器对应一个bean
-prototype:每一次请求都会产生一个新的bean实例
-request:每一次HTTP请求都会产生一个新的bean
-session:针对每一次HTTP请求都会产生一个新的bean - 作用域的配置
-xml 方式配置
-注解方式配置 - SpringIOC 容器
-容器创建对象的方式
-依赖注入的方式
-注解版本使用 - 注解方式实现AOP编程
-使用注解
-使用xml方式配置
一、Spring的概述
-
springIOC(控制反转)
所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
由Ioc容器来控制了外部资源获取(不只是对象包括比如文件等),由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。 -
DI(依赖注入)
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。 -
AOP(切面编程)
二、Spring的环境搭建
- 引入架包依赖
<!-- 引入Spring-AOP等相关Jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_2</version>
</dependency>
- spring配置文件
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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">
<bean id="userEntity" class="com.spring.UserEntity" />
<!-- 扫包 -->
<context:component-scan base-package="com.spring"></context:component-scan>
<!-- 开启事物注解权限 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
- 需要交给Spring管理注入类
package com.spring;
public class UserEntity {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserEntity [name=" + name + ", age=" + age + "]";
}
}
- 测试类
package com.spring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserEntity userEntity = (UserEntity) applicationContext.getBean("userEntity");
userEntity.setName("ly");
userEntity.setAge(18);
System.out.println(userEntity);
}
}
运行结果:
三、spring作用域
spring Ioc创建模式默认为单例模式(可以使用无参构造函数验证),单例是线程不安全的。
-
singleton
当一个bean的 作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,spring的IOC容器中只会存在一个该bean。 -
prototype
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的 getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。) -
request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。 -
session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。 -
作用域的配置
5.1 xml 方式配置
<!-- 无参构造函数的方式 -->
<bean id="userEntity" class="com.spring.UserEntity" scope="singleton"/>
<!-- 有参构造函数的方式 -->
<bean id="userEntity3" class="com.spring.UserEntity" >
<constructor-arg name="name" value="lucy"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
</bean>
5.2 注解方式配置
@Scope(@Scope(ConfigurableListableBeanFactory.SCOPE_SINGLETON))
public class UserEntity {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserEntity [name=" + name + ", age=" + age + "]";
}
}
四、SpringIOC 容器
SpringIOC容器,是spring核心内容。
作用: 创建对象 ; 处理对象的依赖关系。
-
容器创建对象的几种方式
1) 调用无参数构造器
2) 带参数构造器
3) 工厂创建对象
工厂类,静态方法创建对象
工厂类,非静态方法创建对象 -
依赖注入的几种方式
1) 通过构造函数
2) 通过set方法给属性注入值
3) p名称空间
4) 注解 -
注解版本使用
注解方式可以简化spring的IOC容器的配置。
使用注解步骤:
1)先引入context名称空间
xmlns:context="http://www.springframework.org/schema/context"
2)开启注解扫描
<context:component-scan base-package="com.spring"></context:component-scan>
3)使用注解
通过注解的方式,把对象加入ioc容器。
创建对象以及处理对象依赖关系,相关的注解:
@Component 指定把一个对象加入IOC容器
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
@Resource 属性注入
总结:
1) 使用注解,可以简化配置,且可以把对象加入IOC容器,及处理依赖关系(DI)
2) 注解可以和XML配置一起使用。
4. 实现AOP编程
4.a 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* com.spring..*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
4.1 开启事物注解权限
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4.2 代码实现
切面类springAop:
//指定一个类为切面类
@Aspect
//注入Spring IOC容器
@Component
public class springAop {
//定义切入点
@Pointcut("execution(* com.spring..*(..))")
public void performance() {
}
//前置通知: 目标方法之前执行
@Before("performance()")
public void begin() {
System.out.println("前置通知");
}
//后置通知:目标方法之后执行(始终执行)
@After("performance()")
public void commit() {
System.out.println("后置通知");
}
// 返回后通知: 执行方法结束前执行(异常不执行)
@AfterReturning("performance()")
public void afterReturning() {
System.out.println("运行通知");
}
//异常通知: 出现异常时候执行
@AfterThrowing("performance()")
public void afterThrowing() {
System.out.println("异常通知");
}
//环绕通知: 环绕目标方法执行
@Around("performance()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("我是环绕通知-前");
// HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String methodName = pjp.getSignature().getName();
System.out.println("aop===方法名:"+methodName);
pjp.proceed();
String className = pjp.getTarget().getClass().getName();
System.out.println("aop===类名:"+className);
System.out.println("我是环绕通知-后");
}
}
测试类:
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.add();
}
}
运行结果:
4.b 使用xml方式配置
4.1) 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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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.spring"></context:component-scan>
<!-- 切面类 -->
<bean id="aop" class="com.spring.springAopXml"></bean>
<!-- Aop配置 -->
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* com.spring..*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回后通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
4.2)切面类springAopXml:
public class springAopXml {
public springAopXml() {
super();
}
//前置通知: 目标方法之前执行
public void begin() {
System.out.println("前置通知");
}
//后置通知:目标方法之后执行(始终执行)
public void after() {
System.out.println("后置通知");
}
// 返回后通知: 执行方法结束前执行(异常不执行)
public void afterReturning() {
System.out.println("运行通知");
}
//异常通知: 出现异常时候执行
public void afterThrowing() {
System.out.println("异常通知");
}
//环绕通知: 环绕目标方法执行
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("我是环绕通知-前");
// HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String methodName = pjp.getSignature().getName();
System.out.println("===方法名:"+methodName);
pjp.proceed();
String className = pjp.getTarget().getClass().getName();
System.out.println("===类名:"+className);
System.out.println("我是环绕通知-后");
}
}
4.3)测试类
public class SpringTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.add();
}
}
运行结果: