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



