Spring核心思想——IOC、DI、AOP(实例代码)

1.IOC+DI

 

什么是IOC?

        Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想在Java开发中,IOC意味着将你准备好的对象(或者是写好的类)交给容器控制,而不是传统的在你的对象内部直接进行控制。也就是说将对象的创建权反转(交给)给Spring。

什么是DI?

DI—Dependency Injection,即“依赖注入”,组件之间的依赖关系由容器在运行期决定。形象的说,即由容器动态的将某个依赖关系注入到组件中。依赖注入并非是为了给软件系统带来更多的功能,而是为了提高组件的重用效率,并为系统搭建一个灵活、可扩展的平台。

甚至,可以说IOC思想是通过DI技术实现的,或者说DI是另一种说法的IOC。

 

理解DI需要知道的是:“谁依赖谁,为什么需要依赖,谁注入了谁,注入了什么”

  • 谁依赖谁:当然是应用程序依赖于IOC容器(spring容器)
  • 为什么要依赖:应用程序需要IOC容器来提供对象需要的外部资源
  • 谁注入了谁:当然是IOC容器注入了某个应用程序依赖的对象到应用程序中
  • 注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)

 

举例表达:

IOC:你要去学校找一个老师。要在校门口的门卫室告诉门卫你需要找谁,因为所有的老师信息都在这里登记过。这里的门卫室就类似于SpringIoc容器,会把所有的对象类注册。在你需要的时候即你提到某个老师的名字的时候,SpringIoc容器才会把你需要的东西。也就是说所有类的创建、销毁都由Spring来控制,也就是说控制对象生命周期的不再是对象,而是Spring,这就是控制反转。

DI:你找的老师名字是张三。然后门卫记录册上翻到了,于是门卫给老师打电话喊了过来。此时这个老师就和你口中的张三对上号了,这就是注入。当然了老师也是有属性的,你可以喊一个男的张三老师,男的教语文的张三老师。这些属性都是可以在记录册上注册在案的。当然了这个在 SpingIoc容器中并不是提前准备好的张三老师,而是在需要的时候生成的,然后注入到需要的对象中,这样就通过DI技术完成了对象的控制。此时,某个(学校)类需要张三老师这个对象完成某些(教学)方法,而张三老师这个对象是由SpringIoc容器注入到某个(学校)类中的,依赖注入就由此而来。Java1.3以后出现的一个重要特征就是反射(reflection),它允许程序在运行时动态的生成对象、执行对象的方法、改变对象的属性,Spring就是通过反射来实现注入的。

如果整理的太过凌乱,还是无法完全理解,看这篇博客

 

接下来代码演示:

1.对象类

package com.no_interface.demo;

public class BookService {

	public void addBook() {
		System.out.println("add Book");
	}
}

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 definitions here -->
	<!-- 配置Service
		<bean>配置需要创建的对象
		id:用于之后从spring容器中获得实例
		class:需要创建的全限定类名
	 -->
	<bean id="BookServiceId" class="com.no_interface.demo.BookService"></bean>

</beans>

3.测试类

package com.no_interface.demo;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoc {

	@Test
	public void demo1() {
		//之前开发
		BookService bookService = new BookService();
		bookService.addBook();
	}
	
	@Test
	public void demo2() {
		//spring容器获得
		//1.获得容器,默认路径再src下,因此复制完整路径以后可以删除src之前的
		String xmlPath = "com/no_interface/demo/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		
		//2.获得内容,不需要自己new,从spring容器中getBean
		BookService userService = (BookService) applicationContext.getBean("BookServiceId");
		userService.addBook();
	}
}

 

2.AOP

 

什么是AOP?

AOP——Aspect Oriented Programming,面向切面编程。简单来说就是"横向重复,纵向抽取"。在程序中主要用来解决一些系统层面的问题,比如日志,事务。权限等。如果不懂的话几个例图解决:当某一功能重复使用冗余代码量时,可以将其相同流程抽出。然后后面在需要的地方注入。这就是所谓的AOP

 

 

 AOP基本概念:

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)Proxy(代理):

(6)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类(但不能被final修饰)。优先使用动态代理。

 

代码演示:

 

1.接口

package com.spring_day2.aop;

public interface UserService {

	public void save();
	public void delete();
	public void update();
	public void find();
}

2.实现类(目标对象类)

package com.spring_day2.aop;

/**
 * 目标对象类
 * @author 33452
 *
 */
public class UserServiceImpl implements UserService {

	@Override
	public void save() {
		// TODO Auto-generated method stub
		System.out.println("保存用户");
		int i = 1/0;
	}

	@Override
	public void delete() {
		// TODO Auto-generated method stub
		System.out.println("删除用户");
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		System.out.println("更新用户");
	}

	@Override
	public void find() {
		// TODO Auto-generated method stub
		System.out.println("查找用户");
	}

}

3.通知类

package com.spring_day2.aop;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 通知类
 * @author 33452
 *
 */
public class MyAdvice {
/**
 * 	前置通知							|-目标方法运行之前调用
 * 	后置通知(如果出现异常,不会调用)		|-目标方法运行之后调用
 * 	环绕通知							|-目标方法运行之前和之后都调用
 * 	异常拦截通知						|-目标方法出现异常调用
 * 	后置通知(无论是否出现异常,都会调用)	|-目标方法运行之后调用
 */
	
	//前置通知
	public void before() {
		System.out.println("前置通知");
	}
	
	//后置通知
	public void afterNoExceptionReturning() {
		System.out.println("后置通知(方法出现异常,不会调用)");
	}
	
	//环绕通知
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕通知之前的部分");
		Object proceed = pjp.proceed();//这是调用目标方法代码,不要问,记住,我不知道为啥
		System.out.println("环绕通知之后的部分");
		return proceed;
	}
	
	//异常通知
	public void afterException() {
		System.out.println("异常通知");
	}
	
	//后置通知
	public void afterAnythingReturning() {
		System.out.println("后置通知(方法出现异常,也会调用)");
	}
}

4.配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns:p="http://www.springframework.org/schema/p" 
		xmlns="http://www.springframework.org/schema/beans" 
		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-4.2.xsd 
							http://www.springframework.org/schema/context 
							http://www.springframework.org/schema/context/spring-context-4.2.xsd 
							http://www.springframework.org/schema/aop 
							http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
	<!-- 准备工作,引入xmlns:aop命名空间(aop约束) -->
	<!-- 配置目标对象 -->
	<bean name="userServiceImpl" class="com.spring_day2.aop.UserServiceImpl"></bean>
	<!-- 配置通知对象 -->
	<bean name="myAdvice" class="com.spring_day2.aop.MyAdvice"></bean>
	<!-- 配置将通知织入目标对象 -->
	<aop:config>
		<!-- 配置切入点
			表达式	public void com.spring_day2.aop.UserServiceImpl.save()
					void com.spring_day2.aop.UserServiceImpl.save()	(默认服务public)
					* com.spring_day2.aop.UserServiceImpl.save()	(对返回值不做要求)
					* com.spring_day2.aop.UserServiceImpl.*()		(表示针对该类下所有空参方法)
					* com.spring_day2.aop.UserServiceImpl.*(..)		(表示对方法参数不做要求)
					
			最终形态:
					* com.spring_day2.aop.*ServiceImpl.*(..)		(表示对该包下所有类名含有ServiceImpl的类的所有方法)
					* com.spring_day2.aop..*ServiceImpl.*(..)		(表示对该包下以及该包下的子包)
		 -->
		<aop:pointcut expression="execution(* com.spring_day2.aop.*ServiceImpl.*(..))" id="pc"/>
		<!-- 描述通知 -->
		<aop:aspect ref="myAdvice">
			<!-- myadvice中的before方法指定aop的前置通知before方法,然后切入到切入点中 -->
			<!-- 前置 -->
			<aop:before method="before" pointcut-ref="pc"/>
			<!-- 后置(无异常) -->
			<aop:after-returning method="afterNoExceptionReturning" pointcut-ref="pc"/>
			<!-- 异常拦截通知 -->
			<aop:after-throwing method="afterException" pointcut-ref="pc"/>
			<!-- 环绕通知 -->
			<aop:around method="around" pointcut-ref="pc"/>
			<!-- 后置(有异常) -->
			<aop:after method="afterAnythingReturning" pointcut-ref="pc"/>
		</aop:aspect>
	</aop:config>
</beans>

5.测试类

package com.spring_day2.aop;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//测试类
@RunWith(SpringJUnit4ClassRunner.class)//新建spring容器
@ContextConfiguration("classpath:com/spring_day2/aop/applicationContext.xml")//指定容器使用的配置文件
public class TestDemo {

	@Resource(name="userServiceImpl")
	private UserService userServiceImpl;
	
	@Test
	public void demo() {
		userServiceImpl.delete();
	}
}

 

题外话:

Spring需要导入的jar包(核心、依赖):

|—4个核心

 

|—2个依赖

 

Spring Aop需要导入的包:

|—2个核心

|—以及2个第三方包

   

 Spring测试类需要导入的包:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值