【Spring】了解Spring及注解

Spring 

  是一个IOC和 AOP(面向切面编程) 的开源框架

IOC (Inverse Of Control ) 控制反转

  指创建依赖对象控制权的转换,在原来系统中,依赖对象的创建,是需要调用者来负责维护的;采用了控制反转的系统,依赖的对象创建,将不再由调用者来维护,而是由容器负责维护;

class Dao{
}
class Service{
Dao dao = new Dao(); // 通过 new 来创建依赖对象的实例
Dao dao = DaoFactory.getDao(); // 通过工厂的方式获取对象
}

 

DI(Dependency Inject)依赖注入

  与 IoC 描述的是同一件事,只不过描述这件事的角度不同,从调用者的角度来看,是控制反转,从 容器的角度来看,是依赖注入;

  好莱坞法则:Don't call me,We will call you!

 

AOP(Aspect-OrientedProgramming)面向切面编程

  在程序开发中主要用来解决一些系统层面上的问题,比如日志收集,事务管理,权限,缓存,对象池管理等

  AOP利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。

  便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

 

概念

  切面(Aspect): 是一个横切性的关注点的抽象,实质上与类是同一个级别的概念,只不过关注点不同;类是对象的抽象

  连接点(Joinpoint):程序执行过程中某个特定的点,连接切面与程序执行的点;

  通知(Advice):在拦截到连接点后,所执行的操作;
    前置通知
    后置通知
    例外通知
    最终通知
    环绕通知


  切入点(Pointcut):匹配连接点的断言(通俗的讲,定义连接点的规则)

  引入(引介,Introduction) :用来给一定类增加额外的属性或方法;

  AOP 代理(AOP Proxy):由 AOP 框架所创建的代理对象;

  织入(Weaving):将切面应用到程序或对象上,并且执行通知;

 

AOP :Aspect Oriented Program,面向切面(方面)的编程;
1、概念
切面(Aspect):是一个横切性的关注点的抽象,实质上与类是同一个级别的概念,只不过关注点不同;类是对象的抽象
 
连接点(Joinpoint):程序执行过程中某个特定的点,连接切面与程序执行的点;
 
通知(Advice):在拦截到连接点后,所执行的操作;
    前置通知
    后置通知
    例外通知
    最终通知
    环绕通知
切入点(Pointcut):匹配连接点的断言(通俗的讲,定义连接点的规则)
 
引入(引介,Introduction) :用来给一定类增加额外的属性或方法;
 
AOP 代理(AOP Proxy):由 AOP 框架所创建的代理对象; 
 
织入(Weaving):将切面应用到程序或对象上,并且执行通知;
 
2、AOP 编程的基本步骤
    1) 在 classpath 下,添加 spring aop 的依赖 jar 包
        aopalliance.jar
        aspectjweaver.jar
        aspectjrt.jar
    2) 在 spring 的配置文件中,增加 aop 相关的 schema
    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   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.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
 
    3) 在 spring 的配置文件中,启动对 aop 的支持
    <!-- 配置切面 bean -->
    <bean id="logAspect" class="com.practice.logs.LogAspect" />
    <!-- 切面的配置 -->
    <aop:config>
        <!-- 定义一个切面 -->
        <aop:aspect ref="logAspect">
            <!-- 定义一个切入点 -->
            <aop:pointcut expression="execution(* com.practice.dao.*.*(..))" id="daoMethod"/>
            <!-- 定义前置通知 -->
            <aop:before method="doBefore" pointcut-ref="daoMethod"/>
            <!-- 定义最终通知 -->
            <aop:after method="doFinally" pointcut-ref="daoMethod"/>
            <!-- 定义例外通知 -->
            <aop:after-throwing method="doException" pointcut-ref="daoMethod"/>
            <!-- 定义后置通知 -->
            <aop:after-returning method="doAfter" pointcut-ref="daoMethod"/>
            <!-- 定义环绕通知 -->
            <aop:around method="doAround" pointcut-ref="daoMethod"/>
        </aop:aspect>     
    </aop:config>
     
    4) 编写切面
        /**
 * @Aspect 用来注解这是一个切面 
 */
@Component
@Aspect 
public class LogAspect {
    @Pointcut("execution(* com.practice.dao..*.add*(..))")
    private void anyMethod(){}
    //前置通知
    @Before("anyMethod()")
    public void doBefore(){
        System.out.println("执行方法之前");
    }
    //后置通知
    @AfterReturning(pointcut = "anyMethod()")
    public void doAfter(){
        System.out.println("后置通知");
    }
    //例外通知
    @AfterThrowing(pointcut="anyMethod()")
    public void doException(){
        System.out.println("例外通知");
    }
    //最终通知
    @After("anyMethod()")
    public void doFinally(){
        System.out.println("最终通知");
    }
    //环绕通知
    @Around("anyMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知开始");
        Object obj = pjp.proceed();
        System.out.println("环绕通知结束");
        return obj;
    }
}
APO编程的基本步骤

 

OOP(Object Oriented Programming)面向对象编程

   OOP 引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合

   OOP 允许开发者定义纵向的关系,但并不适合定义横向的关系

 

Spring MVC流程图

 

 

控制器类交给Spring管理

  第一种方式是在SpringMVC 的配置文件中定义MyController 的bean 对象。

<bean class="com.host.app.web.controller.MyController"/>

 

  第二种方式是在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。

<context:component-scan base-package = "com.host.app.web.controller" >
<context:exclude-filter type = "annotation"
expression = "org.springframework.stereotype.Service" />
</context:component-scan >

 

 

使用Spring开发步骤

1) 搭建项目

2) 将 spring 的依赖 jar 包,添加到 classpath 目录下

  spring_home/libs/xxx.jar

  commons-logging-1.1.1.jar

3) 在 src 目录下,增加 spring 的配置文件,文件名自定义;(beans.xml , applicationContext.xml)

<?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 标记用来配置一个对象
            id 属性,指定对象的名字
            class 属性,指定对象的类型
     -->
    <bean id="userDao" class="com.practice.dao.UserDaoImpl" />
</beans>

4) 通过如下方式,在 spring 的容器中,取得所创建的对象

  ApplicationContext ctx = new FileSystemXmlApplicationContext("src/beans.xml");
  UserDao userDao = (UserDao) ctx.getBean("userDao");
  userDao.add("admin");

 

 

bean 的配置详解

<bean id="userDao" class="com.practice.dao.UserDaoImpl" scope="singleton"
  lazy-init="true" init-method="init" destroy-method="destroy"/>

 bean 标记用来配置一个对象

id 属性,指定对象的名字
class 属性,指定对象的类型
scope 属性,用来指定创建 bean 的范围,取值如下:
  singleton : 每次调用 getBean 都返回同一个实例(单例,默认值)【servlet】
  prototype : 每次调用 getBean 都返回一个新的实例(原型)【struts】
  request : 每次请求返回一个新的实例(仅在 web 应用中有效)
  session : 每次会话返回一个新的实例 (仅在 web 应用中有效)
  global session :与 session 的范围一致(仅支持 spring mvc)
lazy-init 属性,指定是否延迟创建 bean 的实例;
  true :当首次调用 getBean 时,创建实例;
  false :当初始化 spring 容器时,就创建实例;(默认值)
  注:lazy-init 属性,仅对 singleton 范围内的 bean 有效,其它范围内的 bean总是延迟初始化的;
init-method 属性: 指定创建完成 bean 实例后,要执行的初始化方法,属性值就是方法名;
destroy-method 属性: 指定当销毁 spring 容器时,要执行的销毁方法,属性值就是方法名;
注:lazy-init 、init-method、destroy-method 属性,可以通过在 beans 标记中,设置默认值来实现;

 

 

 Spring bean 的生命周期 

  

 

 注入依赖对象

 基于 setter 方法注入

<bean id="userService" class="com.practice.service.UserServiceImpl">
    <!-- property 用来配置依赖属性
        name 指定需要注入的属性名
        ref  指定使用那一个 bean 对象来注入,对应 bean 的 id 属性
     -->
    <property name="userDao" ref="userDao" /> 
</bean>

类部分代码

private UserDao userDao;

public void setUserDao(UserDao userDao) {
    System.out.println("-------" + userDao);
    this.userDao = userDao;
} 

 基于构造器的注入

<bean id="userService" class="com.practice.service.UserServiceImpl">
    <!-- 
        constructor-arg  用来配置基于构造器的注入
            index 属性,指定构造参数的索引,从 0 开始
            ref 属性,指定用那一个 bean 对象来注入,对应 bean 的 id 属性
     -->
    <constructor-arg index="0" ref="userDao" />   
</bean>

 

 在类中,需要提供相应的构造器

private UserDao userDao;

public UserServiceImpl(UserDao userDao) {
    this.userDao = userDao;
}

 

 自动注入

<!-- 
    autowire 指定自动注入的方式
        byType : 通过方法的参数确定用那一个  setter 方法注入;
        byName :通过方法的名称,确定用那一个 setter 方法注入;
        constructor : 通过构造器注入
 -->
<bean id="userService" class="cn.practice.service.UserServiceImpl"
            autowire="constructor" />

 

  Tips: 如果使用的是自动注入,则通过 xml 的配置,不能够看出对象之间的依赖关系,降低代码的可读性,所以一般不建议使用;

<bean id="pj" class="cn.practice.dao.PropInject">
    <property name="strVal" value="strvalue"/>
    <property name="intVal" value="20" />
    <property name="strArr">
        <list>
            <value>strArr01</value>
            <value>strArr02</value>
            <value>strArr03</value>
        </list>
    </property>
    <property name="lists">
        <list>
            <value>list01</value>
            <value>list02</value>
            <value>list03</value>
        </list>
    </property>
    <property name="sets">
        <set>
            <value>set01</value>
            <value>set02</value>
        </set>
    </property>
    <property name="maps">
        <map>
            <entry key="key01" value="value01" />
            <entry key="key02" value="value02" />
        </map>
    </property>
    <property name="props">
        <props>
            <prop key="prop01">propvalue1</prop>
            <prop key="prop02">propvalue2</prop>
            <prop key="prop03">propvalue3</prop>
        </props>
    </property>
</bean>
注入常见类型属性

 

传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事务

Tips:缺点
  1、如果所有的内容都配置在.xml文件中,会导致.xml文件过大;如果按需求分开.xml文件,又会导致.xml文件过多。总之这会使得配置文件的可读性与可维护性变得很低。
  2、开发中,在.java文件和.xml文件之间不断切换,是一件麻烦的事。同时这种思维上的不连贯也会降低开发的效率。

 

 


Annotation(注解)

格式

// 注解格式
@注解名

 

引入

  JDK1.5及以后版本引入,可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。

  不会直接影响到程序的语义,只是作为注解(标识)存在,可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问

 

作用

  用了注解之后,就不需要在xml文件中配置Bean了 ,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

分类

注解参数的个数可以将注解分为:标记注解、单值注解、完整注解 三类。

Spring中的注解主要分为:类级别的注解、类内部的注解 两类。

  类级别的注解: 如@Component、@Repository、@Controller、@Service以及JavaEE6的@ManagedBean和@Named注解,都是添加在类上面的类级别注解。

  类内部的注解: 如@Bean、@Autowire、@Value、@Resource以及EJB和WebService相关的注解等,都是添加在类内部的字段或者方法上的类内部注解。

 

基于注解方式的配置

1、在 xml 中,增加 contenxt 命名空间

2、在 xml 中,开启动 spring 对注解配置的支持

3、在 xml 中,指定都有那些包中的类,纳入到 spring 的容器来管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启 spring 对注解的支持 -->
    <context:annotation-config />
    <!-- 
        配置扫描那个包及其子包下的类,在扫描的过程中,如果类上面有如下注解,将会被自动纳入到 spring
            的容器来管理
            @Repository     :专门用来注解 dao层 的对象
            @Service        :专门用注解 service 层的对象
            @Controller     : 专门用来注解 controller 对象
            @Component      : 当某个类的分工不是很明确,或者不是上面的三类,则使用此注解
    -->
    <context:component-scan base-package="cn.practice" />
</beans>

 4、在需要 Spring 容器管理的类上,增加相应的注解

@Repository("userDao") // 相当于<bean id="userDao" class="" />
@Scope("singleton") // 通过 @Scope 注解,注解 bean 的范围
public class UserDaoImpl implements UserDao {
    ...
}

 

 5、使用 @Resource 注解依赖对象

@Resource(name="userDao")
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

 

 

 什么是Spring   https://www.bilibili.com/read/cv9300303/

 什么是Spring 注解  https://blog.csdn.net/wokewoke/article/details/104774417

 Spring 注解  https://blog.csdn.net/weixin_42626412/article/details/124206162

posted @ 2022-10-09 15:01  Phoenixy  阅读(35)  评论(0编辑  收藏  举报