SSM框架学习之Spring浅谈

Spring介绍

1、什么是Spring?

百度:

Spring是JavaEE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。

补充:想要具体了解学习Spring,建议多逛逛Spring官网,不一定要全部看懂,一开始只是混个脸熟也有利于后面进一步的学习。

2、我们常说的Spring指什么?

如果我们打开Spring官网,打开project会发现:Spring就像是一个大的容器型框架,下面还有比较熟知的常见项目和框架,例如:Springboot,SpringCloud,SpringData等等。其中“SpringFramework”的Core technologies(核心技术),会发现一些比较常见的关键词:DI(IOC)和AOP,就是常说的控制反转和面向切面编程。所以,我们常说的“Spring”大部分情况下是指“SpringFramework”。 

Springframework核心技术

IOC(控制反转):

一般程序的设计思想是从Controller/Servlet层到Service层再到Dao/Mapper层,如果对某个下游的类进行更改名字,或者进行更换,则整个流程都需要进行相应的更改,所以代码的耦合性太高,牵一发而动全身,所以为了解决这个问题设计出了IOC(控制反转)的思想:把创建下游类的功能交给一个“类似工厂”(BeanFactory)的对象进行管理(工厂思想+反射)。

1 public class MyController {
2     public static void main(String[] args) {
3         MyBeanFactory myBeanFactory = new MyBeanFactory();
4         SpringDao springDao = (SpringDao) myBeanFactory.getBean();
5         springDao.test();
6     }
7 
8 }
Controller
 1 public class MyBeanFactory {
 2     public Object getBean() {
 3         Object bean = null;
 4         try {
 5             bean = Class.forName("com.emo.dao.SpringDao").newInstance();
 6         } catch (InstantiationException e) {
 7             e.printStackTrace();
 8         } catch (IllegalAccessException e) {
 9             e.printStackTrace();
10         } catch (ClassNotFoundException e) {
11             e.printStackTrace();
12         }
13         return bean;
14     }
15 }
BeanFactory
1 public class SpringDao {
2     public void test() {
3         System.out.println("SpringDao被调用!");
4     }
5 }
Dao

优点:不需要每次更改Dao层数据都需要整个流程都进行更改,只需要修改BeanFactory中的“com.emo.dao.SpringDao”。

缺点:还是需要进行手动修改代码。

工厂思想还是需要改代码,于是在这个基础上加上配置文件(ApplicationContext.xml)进行改造,这样只需要修改配置文件基本不需要修改代码。

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4     xsi:schemaLocation="
5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
6 
7     <!-- bean definitions here -->
8     <bean id="springDao" class="com.emo.dao.SpringDao"></bean>
9 </beans>
ApplicationContext.xml
public class SpringDao {
    public void test() {
        System.out.println("SpringDao被调用!");
    }
}
Dao
1 public class MyController {
2     public static void main(String[] args) {
3         //spring配置方式,创建spring工厂,加载spring配置文件
4          ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
5          //从spring工厂中获取对象,通过bean的id/name
6          SpringDao springDao = (SpringDao) ac.getBean("springDao");
7          springDao.test();
8     }
9 }
Controller

注意:记得要导入SpringFramework依赖

1         <dependency>
2             <groupId>org.springframework</groupId>
3             <artifactId>spring-context</artifactId>
4             <version>5.1.7.RELEASE</version>
5         </dependency>

DI(依赖注入):

如何通过调用Service,继而调用Dao层?为了解决这个问题,就有了依赖注入,把Dao成当作Service层的“属性”或者“元素”,注入到配置文件中。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 6 
 7     <!-- bean definitions here -->
 8     <bean id="springDao" class="com.emo.dao.SpringDao"></bean>
 9     <bean id ="springService" class="com.emo.service.SpringService">
10     <!-- 注入对象 -->
11     <!-- property 根据类中的setter方法进行属性注入 -->
12     <!-- name:setter方法的后缀小写,比如setXxx 对应的name为xxx -->
13     <!-- ref:引用哪一个bean(对象),值为bean的id/name -->
14     <property name="springDao" ref="springDao" />
15 </bean>
16     
17 </beans>
ApplicationContext.xml
1 public class SpringDao {
2     public void test() {
3         System.out.println("SpringDao被调用!");
4     }
5 }
SpringDao
 1 public class SpringService {
 2     SpringDao springDao = null;
 3 
 4     public void setSpringDao(SpringDao springDao) {
 5         this.springDao = springDao;
 6     }
 7 
 8     public void test() {
 9         System.out.println("SpringService被调用!");
10         springDao.test();
11     }
12 
13 }
SpringService
1 public class MyController {
2     public static void main(String[] args) {
3         //spring配置方式,创建spring工厂,加载spring配置文件
4         ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
5          //从spring工厂中获取对象,通过bean的id/name
6          SpringService springService = (SpringService) ac.getBean("springService");
7          springService.test();
8     }
9 }
MyController

注意:把Dao层注入到Service层时,要把Dao层当作Service层的属性或者元素,所以要在Service层提供setXxxDao()方法。

 1 public class SpringService {
 2     SpringDao springDao = null;
 3 
 4     public void setSpringDao(SpringDao springDao) {
 5         this.springDao = springDao;
 6     }
 7 
 8     public void test() {
 9         System.out.println("SpringService被调用!");
10         springDao.test();
11     }
12 
13 }

简要总结:IOC就是由原本手动创建对象交给Spring工厂去创建对象,DI就是把一个对象A当作另一个对象B的属性或者元素注入到配置文件的B对象中。

AOP(面向切面编程):

AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。AOP 是 OOP(面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构),思想延续,它是基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强!

关于代理相关资料:https://www.cnblogs.com/Bernard94/p/12358728.html

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、权限管理、事务管理、安全检查、缓存、日志记录等)。

相关术语:

  1. Aspect(切面): 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能
  2. joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
  3. Pointcut(切入点):所谓切入点是指我们要对哪些joinpoint进行拦截的定义.通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.
  4. Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  5. Target(目标对象):代理的目标对象
  6. weaving(织入):是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象
  7. Introduction(引介):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

 JDK动态代理实现AOP:

1 public interface People {
2     public void eat() ;
3 }
People
1 public class Student implements People {
2 
3     public void eat() {
4         System.out.println("吃东西!");
5     }
6 
7 }
Student
 1 public class ProxyObject {
 2     private Object target;
 3 
 4     public ProxyObject(Object target) {
 5         this.target = target;
 6     }
 7 
 8     public Object getProxyObject() {
 9         // 参数1:目标对象的类加载器
10         // 参数2:目标对象实现的接口
11         // 参数3:回调方法对象
12         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
13                 new InvocationHandler() {
14 
15                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
16                         // 如果是保存的方法,执行记录日志操作
17                         if (method.getName().equals("eat")) {
18                             ProxyEat();
19                         }
20                         // 目标对象原来的方法执行
21                         Object object = method.invoke(target, args);// 调用目标对象的某个方法,并且返回目标对象方法的返回值
22 
23                         return object;
24                     }
25                 });
26     }
27 
28     private void ProxyEat() {
29         System.out.println("eat方法加强!");
30     }
31 }
ProxyObject
1 public class test {
2     public static void main(String[] args) {
3         Student student = new Student();
4         ProxyObject proxyObject = new ProxyObject(student);
5         People proxyStudenty = (People) proxyObject.getProxyObject();
6         proxyStudenty.eat();
7     }
8 }
test

注意:因为JDK必须对接口生成代理,所以代理对象返回的是接口:People,不能是具体类:Student。

 CGLIB动态代理实现AOP:

1 public class Dog {
2     public void bark() {
3         System.out.println("汪汪。。。");
4     }
5 }
Dog
 1 public class ProxyObject implements MethodInterceptor {
 2     private Object target;
 3 
 4     public ProxyObject(Object target) {
 5         this.target = target;
 6     }
 7 
 8     // 获取代理对象
 9     public Object getProxyObject() {
10         // 1.代理对象生成器(工厂思想)
11         Enhancer enhancer = new Enhancer();
12         // 2.在增强器上设置两个属性
13         // 设置要生成代理对象的目标对象:生成的目标对象类型的子类型
14         enhancer.setSuperclass(target.getClass());
15         // 设置回调方法
16         enhancer.setCallback(this);
17         // Callback
18         // 3.创建获取对象
19         return enhancer.create();
20     }
21 
22     // 回调方法(代理对象的方法)
23     // 参数1:代理对象
24     // 参数2:目标对象的方法对象
25     // 参数3:目标对象的方法的参数的值
26     // 参数4:代理对象的方法对象
27     public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
28         // 如果是保存的方法,执行记录日志操作
29         if (method.getName().equals("bark")) {
30             ProxyBark();
31         }
32         // 目标对象原来的方法执行
33         Object object = method.invoke(target, args);// 调用目标对象的某个方法,并且返回目标对象方法的执行结果
34         return object;
35     }
36 
37     private void ProxyBark() {
38         System.out.println("Bark方法加强!");
39     }
40 
41 }
ProxyObject
1 public class demo {
2     public static void main(String[] args) {
3         Dog dog = new Dog();
4         ProxyObject proxyObject = new ProxyObject(dog);
5         Dog proxyDog = (Dog) proxyObject.getProxyObject();
6         proxyDog.bark();
7     }
8 }
demo

注意:Cglib要实现“MethodInterceptor”接口,此接口在SpringFramework中,所以要引入spring-context依赖:

1         <dependency>
2             <groupId>org.springframework</groupId>
3             <artifactId>spring-context</artifactId>
4             <version>5.1.7.RELEASE</version>
5         </dependency>

总结:

  • Jdk代理:基于接口的代理,一定是基于接口,会生成目标对象的接口类型的子对象。
  • Cglib代理:基于类的代理,不需要基于接口,会生成目标对象类型的子对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值