用最简单的话说就是IOC就是控制反转。控制就是对对象的创建和销毁的控制。反转就是由原来我们手动创建对象反转到由IOC容器提供对象
控制: 对象的创建对象的销毁
反转: 将创建对象的工作交给IOC容器
我用三种创建对象的方式去展示IOC的核心工厂模式+反射
普通创建对象的方式就是直接new 这个对象。然后调用对象的方法。但是这种的方式耦合度太高。牵一发动全身
/**
* 测试调用用户对象的test方法
* 普通创建对象
*/
public static void main(String[] args) {
// 普通对象创建
User user = new User();
// 调用测试类的方法
user.testCs();
}
/**
* 提供方法
*/
public void testCs(){
System.out.println("调用成功。。。。。。我是用户类");
}
工厂模式创建对象相对的实现了消弱耦合。但是消弱的只是调用方和被调用方的耦合。实际上还是存在耦合就是工厂和被调用方
/**
* 将创建对象的工作交给工厂创建
* @return
*/
public static User findUser(){
return new User();
}
/**
* 测试调用用户对象的test方法
* 工厂创建对象
*/
public static void main(String[] args) {
// 工厂创建对象
User user = TestGc.findUser();
// 调用测试类的方法
user.testCs();
}
核心就是可以通过反射去根据类的路径 去生成对象。这个路径可以设置在xml中然后读取xml中的属性值 下次当你的类路径修改了。我只需要改xml一个地方就解决了所有的地方
/**
* 将创建对象的工作交给工厂创建
* @return
*/
public static User findUser(){
// user类的路径 类的全限定名
// 在配置文件中设置 然后反射加载获取属性值
String luji = "com.macro.mall.user.User";
try {
// 加载指定的类 返回class对象的引用
Class user = Class.forName(luji);
System.out.println("创建成功!!!");
// 创建一个对象实例然后返回
return (User) user.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 测试调用用户对象的test方法
* 工厂创建对象
*/
public static void main(String[] args) {
// 工厂创建对象
User user = TestGc.findUser();
// 调用测试类的方法
user.testCs();
}
IOC实现容器的两种方式BeanFactory和ApplicationContext
什么是BeanFactory?
BeanFactory:是IOC的顶级接口 它定义了一些功能 但是功能比较简单 一般不面向程序使用
特点:只有在第一次调用bean创建对象的时候 他才会对bean实例化 俗称懒汉式
什么是ApplicationContext?
ApplicationContext:是根据BeanFactory衍生出的一个子接口 它扩展了BeanFactory的一些功能 一般面向程序使用
特点:当程序启动的时候就会生成所有bean的实例化 我们只需要使用就可以了 实例的工作都在项目启动的时候做 俗称饿汉式
ApplicationContext有两个实现类FileSystemXmlApplicationContext和ClassPathXmlApplicationContext
这两个都是去读配置文件。只是参数有一些区别
xml工作流程
刚才说了三种的创建方式。普通->工厂->工厂+反射 做这些的目的就是为了更大一步的实现消弱耦合度 IOC其实就是一个容器 而容器里边装的就是你交给IOC需要创建对象的类 什么时候用什么时候从里边拿就可以了。不需要你手动的创建 下边看下如何拿对象
在src下创建.xml文件来以配置的方式创建对象
.xml
<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 id="user" class="com.macro.mall.user.User">bean>
beans>
创建对象是在bean标签下执行。它有两个常用字段
调用类
/**
* 测试调用用户对象的test方法
* IOC创建对象
*/
public static void main(String[] args) {
// 读取配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
// 生成对象
User user = context.getBean("user", User.class);
// 调用测试类的方法
user.testCs();
}
IOC默认是单实例对象。所以如果想要多实例就需要在bean标签设置一个scope=prototype
scope常用的两个字段prototype和singleton
<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 id="user" class="com.macro.mall.user.User" scope="prototype">bean>
beans>
@注解工作流程
虽然配置文件可以实现。但是实现起来太过繁琐。需要写大量的配置。所以SpringIOC还有另一种方式就是使用注解代替配置也是工作常用的一种方式
常用注解:
对象创建注解 实现的效果都是一样的。如果你是小项目。随便使用那个都可以。如果你是大项目。就需要按照规范来做
属性注入注解 依赖注入这篇没有讲到。将会放到下篇单独的一章
Resource如果指定了name 那么就会到容器中匹配相对的name 如果没有则报错
Resource如果指定了type 那么就会到容器中匹配相对的type 没有则报错
Resource如果什么都没指定 默认先找名称。名称没有在找类型
组件扫描注解 想要实现全注解开发就需要将配置文件的组件扫描替换成注解扫描
开启注解扫描
/**
* 开启全局扫描所有注解对象
*/
@Configuration
@MapperScan(basePackages = {"com.macro.mall"})
public class SpringConfig {
}
将类交给IOC容器
@Service(value = "user")
public class User
获取对象
/**
* 测试调用用户对象的test方法
* IOC创建对象
*/
@Test
public void main1() {
// 读取配置文件
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 生成对象
User user = context.getBean("user", User.class);
// 调用测试类的方法
user.testCs();
}
通俗的讲就是AOP是面向切面编程。在不改变原代码的情况下。对业务增强。实现了业务层的消弱耦合 它的核心就是使用了动态代理生成一个代理对象 然后让代理对象对方法增强。
常用的注解
前置通知
@Component
@Aspect // 将当前类作为一个代理对象
public class DaiLi {
/**
* 前置通知
* value = "execution(* com.macro.mall.user.User.testCs())" 配置增强的方法
* 也可以设置当前包下的所有的类的所有方法
*/
@Before(value = "execution(* com.macro.mall.user.User.testCs())")
public void qian(){
System.out.println("在方法执行前执行。。。。。。。。");
}
}
环绕通知
/**
* 环绕通知
*/
@Around(value = "execution(* com.macro.mall.user.User.testCs())")
public void hunRao(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("在方法执行前执行。。。。。。。。");
try {
// 增强的方法执行
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("在方法执行后执行。。。。。。。。");
}
ps
:一个开发界的小学生,一直在学习从未敢停止