java架构学习——23. SpringIOC与AOP

本篇博文主要包含:

  • springIOC(控制反转)
  • DI(依赖注入)
  • AOP(切面编程)
    -Spring的环境搭建
  • spring作用域
    -singleton:表示一个容器对应一个bean
    -prototype:每一次请求都会产生一个新的bean实例
    -request:每一次HTTP请求都会产生一个新的bean
    -session:针对每一次HTTP请求都会产生一个新的bean
  • 作用域的配置
    -xml 方式配置
    -注解方式配置
  • SpringIOC 容器
    -容器创建对象的方式
    -依赖注入的方式
    -注解版本使用
  • 注解方式实现AOP编程
    -使用注解
    -使用xml方式配置

一、Spring的概述

  1. springIOC(控制反转)
    所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
    由Ioc容器来控制了外部资源获取(不只是对象包括比如文件等),由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

  2. DI(依赖注入)
    IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

  3. AOP(切面编程)

二、Spring的环境搭建

  1. 引入架包依赖
		<!-- 引入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>
  1. 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>
  1. 需要交给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 + "]";
	}

}
  1. 测试类
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创建模式默认为单例模式(可以使用无参构造函数验证),单例是线程不安全的。

  1. 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。

  2. prototype
    prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的 getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)

  3. request
    request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。

  4. session
    session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。

  5. 作用域的配置
    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. 容器创建对象的几种方式
    1) 调用无参数构造器
    2) 带参数构造器
    3) 工厂创建对象
    工厂类,静态方法创建对象
    工厂类,非静态方法创建对象

  2. 依赖注入的几种方式
    1) 通过构造函数
    2) 通过set方法给属性注入值
    3) p名称空间
    4) 注解

  3. 注解版本使用
    注解方式可以简化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();
	}
}

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值