1、Ioc概述:
IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。
Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。
IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。
1.1、控制反转(IoC)
控制反转是一种思想,控制反转是为了降低程序的耦合度,提高程序扩展能力,控制反转就是将对象的创建权力转移出去,交给第三方容器去负责,将对象和对象之间的维护交给第三方容器管理。而控制反转又是通过DI(Dependency Injection):依赖注入实现的。
1.2、DI(Dependency Injection):依赖注入
DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想。
依赖注入:是指Spring在创建对象的过程中,将对象依赖属性通过配置的方式进行注入。
Spring依赖注入的方式主要有四个,基于注解注入方式、set注入方式、构造器注入方式、静态工厂注入方式。推荐使用基于注解注入方式,配置较少,比较方便
总结:DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想。
基于注解注入方式
Service层代码
@Service
public class AdminService {
//code
}
Controller层代码
@Controller
@Scope("prototype")
public class AdminController {
@Autowired
private AdminService adminService;
//code
}
@Autowired与@Resource都可以用来装配Bean,都可以写在字段、setter方法上。
区别:
@Autowired默认按类型进行自动装配(该注解属于Spring),默认情况下要求依赖对象必须存在,如果要允许为null,需设置required属性为false,例:@Autowired(required=false)。如果要使用名称进行装配,可以与@Qualifier注解一起使用。
@Autowired
@Qualifier("adminService")
private AdminService adminService;
@Resource默认按照名称进行装配(该注解属于J2EE),名称可以通过name属性来指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行装配;如果注解写在setter方法上,默认取属性名进行装配。当找不到与名称相匹配的Bean时,会按照类型进行装配。但是,name属性一旦指定,就只会按照名称进行装配。
@Resource(name = "adminService")
private AdminService adminService;
除此之外,对于一些复杂的装载Bean的时机,比如我们需要根据配置装载不同的Bean,以完成不同的操作,可以使用getBean(“beanID”)的方式来加载Bean。
通过BeanID加载Bean方法如下:
@Component
public class BeanUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (BeanUtils.applicationContext == null) {
BeanUtils.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String id) throws Exception {
try {
return applicationContext.containsBean(id) ? applicationContext.getBean(id) : null;
} catch (BeansException e) {
e.printStackTrace();
throw new Exception("not found bean id: " + id);
}
}
}
我们在需要装载Bean的地方调用该方法即可
public class BaseController {
protected IService loadService(String id) throws Exception {
IService iService = (IService) BeanUtils.getBean(id);
if (iService != null) {
return iService;
} else {
throw new Exception("加载Bean错误");
}
}
}
2、面向切面编程(AOP):
2.1.AOP概念
在Spring 中,有两个核心概念,一个是IOC/DI , 一个是AOP,AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构。而OOP(Object Oriented PRogramming)面向对象编程,是以各种编程思想,所以,AOP也是一种编程思想,只是两者之间是不同的编程规范。
2.2.AOP作用
在不惊动原始设计的基础上为其进行功能增强。
2.3.AOP核心概念
-
连接点(JoinPoint):程序执行过程中都任意位置,粒度为执行方法、抛出异常、设置变量等。
在SpringAOP中,理解为方法的执行
-
切入点(Pointcut):匹配连接点的式子
在SpringAOP中,一个切入点可以描述一个具体方法,也可以匹配多个方法
连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点
-
通知(Advice):在切入点处执行的操作,也就是共性功能
在SpringAOP中,功能最终以方法的形式呈现
-
通知类:定义通知的类
-
切面(Aspect):描述通知与切入点的对应关系
-
连接点(可选择的所有英雄)
-
切入点(已选择的英雄)
通知(某个增益buff)
通知类(所有增益buff)
切面(带了buff的已选择英雄)
2.4 AOP入门
新建一个Maven项目,在pom.xml中添加依赖.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
</dependencies>
定义接口和实现类
在java包下添加BookDao和BookDaoImpl类(连接点)
public interface BookDao {
public void save();
public void update();
}
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
@Override
public void update() {
System.out.println("book dao update ...");
}
}
添加Spring配置类
@Configuration
@ComponentScan("com")
public class SpringConfig {
}
添加测试类
public class test {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.save();
bookDao.update();
}
}
项目结构如下:
定义通知类和通知
在com包下创建aop.MyAdvice类
public class MyAdvice {
public void method(){
System.out.println(System.currentTimeMillis());
}
}
定义切入点
public class MyAdvice {
//定义切入点update()
@Pointcut("execution(void com.dao.BookDao.update())")
private void pt(){}
public void method(){
System.out.println(System.currentTimeMillis());
}
}
制作切面
切面是用来描述通知和切入点之间的关系
public class MyAdvice {
//定义切入点update()
@Pointcut("execution(void com.dao.BookDao.update())")
private void pt(){}
//制作切面
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
将通知类配给容器并标识其为切面类
@Component
@Aspect
public class MyAdvice {
//定义切入点update()
@Pointcut("execution(void com.dao.BookDao.update())")
private void pt(){}
//制作切面
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
开启注解格式AOP功能
@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy
public class SpringConfig {
}
运行测试
运行test测试类,控制台输出
注:喜欢的朋友可以关注公众号“JAVA学习课堂”方便阅读,内容更丰富哦。