持续性学习-Day20(Spring)


Spring

一、简介

1.1 spring

Spring是一个轻量级控制反转(IOC)和面向切面编程(AOP)的容器框架

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>6.1.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-jdbc</artifactId>
   <version>6.1.8</version>
</dependency>

1.2 优点

  • Spring是一个开源的免费的框架(容器)

  • Spring是一个轻量级的、非入侵式的框架

  • 控制反转(IOC),面向切面变成(AOP)

  • 支持事务的处理,对框架整合的支持

1.3 组成

 

二、IOC理论推导

  1. UserDao接口

  2. UserDaoImpl实现

  3. UserService接口

  4. UserServiceImpl业务实现

业务层使用set实现操作:IOC的原型

private UserDao userDao;

//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
}
  • 之前,程序是主动创建的,控制权在程序员手上

  • 使用了set注入之后,程序不再具有主动性,而是变成了被动的接受对象

  • 降低了系统的耦合性,可以更加专注于业务的实现

 

所谓的控制反转:就是获得依赖对象的方式反转了

控制反转是一种通过描述(XML或注解)并通过第三方去生产获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现的方式是依赖注入(Dependency Injection,DI)

三、IOC创建对象的方式

<!--有参构造,下表赋值-->
<bean id="hello" class="com.stujc.pojo.Hello">
   <constructor-arg index="0" value="Spring"/>
</bean>
<!--有参构造,类型赋值-->
<bean id="hello" class="com.stujc.pojo.Hello">
   <constructor-arg type="java.lang.String" value="Spring"/>
</bean>
<!--有参构造,name赋值-->
<bean id="hello" class="com.stujc.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>

在配置文件加载的时候,容器中管理的对象就已经初始化了

四、Spring配置

4.1 别名

<!--别名-->
<alias name="hello" alias="hello别名"/>

4.2 bean的配置

<!--
   id:bean的唯一标识符,相当于对象名
   class:bean对象所使用的全限定名:包名+类型
   name:别名,同时可以取多个别名
-->

4.3 import

import一般用于团队开发,可以将多个配置文件,导入合并为一个

假设存在项目存在多人开发,使用不同的类,不同的类需要注册在不同的bean中,可以利用import将所有人的beans.xml合并

applicationContext.xml

<import resource="beans.xml"/>

使用时,直接使用总的配置

五、依赖注入(DI)

  • 构造器注入

  • set注入

    • 依赖:bean对象的创建依赖于容器

    • 注入:bean对象中的所有属性,由容器来注入

    <bean id="user" class="com.stujc.pojo.User"/>
   <bean id="hello" class="com.stujc.pojo.Hello">
       <!--第一种,普通值的注入-->
       <property name="name" value="Spring"/>
       <!--第二种,bean的注入-->
       <property name="bean" ref="user"/>
       <!--第三种,数组的注入-->
       <property name="arr">
           <array>
               <value></value>
               <value></value>
           </array>
       </property>
       <!--第四种,list的注入-->
       <property name="list">
           <list>
               <value></value>
               <value></value>
           </list>
       </property>
       <!--第五种,Map的注入-->
       <property name="map">
           <map>
               <entry key="" value=""/>
               <entry key="" value=""/>
           </map>
       </property>
       <!--第六种,Set的注入-->
       <property name="set">
           <set>
               <value></value>
               <value></value>
           </set>
       </property>
       <!--第七种,空或null的注入-->
       <property name="kn">
           <value></value>
           <null/>
       </property>
       <!--第八种,特殊类型的注入-->
       <property name="info">
           <props>
               <prop key="key1">value1</prop>
               <prop key="key2">value2</prop>
           </props>
       </property>
   </bean>

 

  • 拓展方式

5.1 C命名和p命名

xmlns:p="http://www.springframework.org/schema/p"
<!--p命名空间注入,可以直接注入属性的值-->
<bean id="user" class="com.stujc.pojo.User" p:name="小金"/>
xmlns:p="http://www.springframework.org/schema/p"
<!--c命名空间注入,需要有无参有参构造函数-->
<bean id="user1" class="com.stujc.pojo.User" c:id="1" c:name="小金" c:age="18"/>

 

5.2 bean的作用域

  • Scope

    • singleton(单例)

    • prototype(原型)

    • request

    • session

    • application

    • websocket

六、Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式

  • Spring会在上下文中自动寻找,并自动给bean装配属性

三种自动装配的方式:

  1. 在xml中显式的配置

  2. 在java中显式的配置

  3. 隐式的自动装配bean

6.1 测试

public class People {
   private Cat cat;
   private Dog dog;
   private String name;
}
<bean id="cat" class="com.stujc.pojo.Cat"/>
<bean id="dog" class="com.stujc.pojo.Dog"/>
<bean id="people" class="com.stujc.pojo.People" autowire="byName">
   <property name="name" value="小金"/>
   <property name="cat" ref="cat"/>
   <property name="dog" ref="dog"/>
</bean>

6.2 byName自动装配

<bean id="cat" class="com.stujc.pojo.Cat"/>
<bean id="dog" class="com.stujc.pojo.Dog"/>
<!--
   byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanId
-->
<bean id="people" class="com.stujc.pojo.People" autowire="byName">
   <property name="name" value="小金"/>
</bean>

6.3 byType自动装配

要求类型全局唯一

<!--
   byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean
-->
<bean id="people" class="com.stujc.pojo.People" autowire="byType">
   <property name="name" value="小金"/>
</bean>

6.4 小结

  • byName自动装配的时候,要求所有bean的id唯一,且与需要自动注入的属性的set方法的值一致

  • byType自动装配的时候,需要保证所有bean的class唯一,且与需要自动注入的属性的类型一致

6.5 使用注解实现自动装配

jdk1.5,spring2.5支持注解

使用注解:

  1. 导入约束

<?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
      ">
   
</beans>
  1. 配置注解支持

<context:annotation-config/>
//直接在属性上使用即可,可以省略set方法
@Autowired
//指定唯一的bean对象注入
@Qualifier(value = "xxx")
//字段标记了这个注解,说明这个字段可以为null
@Nullable
@Autowired(required=false)

//java的注解,实现自动注入,name指定装配
@Resource(name="")

//放在类上,说明这个类被Spring管理了,就是bean
@Component
//注入值
@Value("小金")
  1. 衍生的注解

@Component有几个衍生的注解,在web开发中,会按照mvc三层架构分层

  • dao【@Repository】

  • service【@Service】

  • controller【@Controller】

  1. 作用域

@Scope(value="singleton")

6.6 小结

xml与注解:

  • xml适用于任何场合,维护简单方便

  • 注解 不是自己的类使用不了,维护相对复杂

xml与注解最佳实践:

  • xml用来管理bean

  • 注解只负责完成属性的注入

<!--指定要扫描的包,这个包下的注解就回生效-->
<context:component-scan base-package="com.stujc"/>
<context:annotation-config/>

七、使用Java的方式配置Spring

//这个Config也会被Spring容器托管,注入到容器中,因为他本来就是一个@Component
//@Configuration代表这是一个配置类,类似beans.xml
@Configuration
@ComponentScan("com.stujc.pojo")
//导入其他配置类
@Import(Config2.class)
public class Config {
   //注入一个bean,相当于xml中的bean标签
   //方法的名字,相当于bean标签中的id
   //方法的返回值,相当于bean标签中的class属性
   @Bean
   public User user() {
       //返回要注入到bean的对象
       return new User();
  }
}
public class Test {
   public static void main(String[] args) {
       //如果完全使用了配置类的方式,只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
       ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
       User user = context.getBean("user", User.class);
       System.out.println(user);
  }
}

八、AOP

SpringAop的底层:代理模式

代理模式的分类:

  • 静态代理

  • 动态代理

8.1 静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色,代理真是角色之后,一般会执行一些附属操作

  • 客户:访问代理对象的人

代理模式的优点:

  • 可以使真实角色更加纯粹,不用去关注一些公共的业务

  • 公共业务交给了代理角色,实现了业务的分工

  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个正式角色就回产生一个代理角色:代码量会翻倍,开发效率降低

8.2 动态代理

  • 动态代理和静态代理角色一样

  • 动态代理的类是动态生成的,不是直接写好的

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口---JDK动态代理

    • 基于类:cglib

    • java字节码实现:javasisst

需要理解两个类:proxy,InvocationHandler

public class ProxyInvocationHandler implements InvocationHandler {
   //被代理的接口
   private Rent rent;

   public void setRent(Rent rent) {
       this.rent = rent;
  }

   //生成得到代理类
   public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
  }

   //处理代理实例,并返回结果
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       seeHouse();
       //动态代理的本质就是使用反射机制实现
       Object ret = method.invoke(rent, args);
       fare();
       return ret;
  }

   public void seeHouse(){
       System.out.println("看房子");
  }

   public void fare(){
       System.out.println("收中介费");
  }
}
public static void main(String[] args) {
   //正式角色
   Host host = new Host();
   //代理角色
   ProxyInvocationHandler pih = new ProxyInvocationHandler();
   //通过调用程序处理角色来处理需要调用的接口
   pih.setRent(host);
   //动态生成的proxy,并没有写代理对象
   Rent proxy = (Rent) pih.getProxy();
   proxy.rent();
}

一个动态代理类代理的是一个接口,一般就是一类业务。

8.3 什么是AOP

AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

public interface UserService {
   public void add();
   public void delete();
   public void update();
   public void select();
}
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
   <bean id="userService" class="com.stujc.service.UserServiceImpl"></bean>
   <bean id="log" class="com.stujc.log.Log"></bean>
   <bean id="afterlog" class="com.stujc.log.AfterLog"></bean>

   <!--方式一:使用原生的Spring API接口-->
   <!--配置aop:需要导入aop的约束-->
   <aop:config>
       <!--切入点:expression,execution(要执行的位置! * * * *)-->
       <aop:pointcut id="pointcut" expression="execution(* com.stujc.service.UserServiceImpl.*(..))"/>
       <!--执行环绕增强-->
       <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
       <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
   </aop:config>
</beans>
public class AfterLog implements AfterReturningAdvice {
   //returnValue:返回值
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
       System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);

  }
}
public class Log implements MethodBeforeAdvice {
   //method:要执行的目标对象的方法
   //args:参数
   //target:目标对象
   @Override
   public void before(Method method, Object[] args, Object target) throws Throwable {
       System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
  }
}
public class Test {
   public static void main(String[] args) {
       ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       //动态代理代理的是接口
       UserService userService = context.getBean("userService", UserService.class);
       userService.add();
  }
}

方法二

<!--方法二:自定义类-->
<bean id="diy" class="com.stujc.diy.DiyPointCut"/>
<aop:config>
   <!--自定义切面,ref要引用的类-->
   <aop:aspect ref="diy">
       <!--切入点-->
       <aop:pointcut id="point" expression="execution(* com.stujc.service.UserServiceImpl.*(..))"/>
       <!--通知-->
       <aop:before method="before" pointcut-ref="point"/>
       <aop:after method="after" pointcut-ref="point"/>
   </aop:aspect>
</aop:config>

 

九、整合Mybatis

  • spring-dao.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">
   <!--DataSource:使用Spring的数据源替换mybatis-->
   <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/school?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
       <property name="username" value="root"/>
       <property name="password" value="stujc0828"/>
   </bean>
   <!--SqlSessionFactory-->
   <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource"/>
       <!--绑定mybatis配置文件-->
       <property name="configLocation" value="classpath:mybatis-config.xml"/>
       <property name="mapperLocations" value="classpath:com/stujc/mapper/*.xml"/>
   </bean>

   <!--SqlSessionTemplate:就是之前使用的sqlsession-->
   <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
       <!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
       <constructor-arg index="0" ref="sqlSessionFactory"/>
   </bean>
</beans>
  • 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"
      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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
   <import resource="spring-dao.xml"/>

   <!--注入bean-->
   <bean id="userMapper" class="com.stujc.mapper.UserMapperImpl">
       <property name="sqlSession" ref="sqlSessionTemplate"/>
   </bean>
</beans>

 

十、声明式事务

  • 声明式事务(AOP)

  • 编程式事务

<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <constructor-arg ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务的类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <!--给哪些方法配置事务-->
   <!--配置事务的传播特性 propagation="REQUIRED"-->
   <tx:attributes>
       <tx:method name="find" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="query" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
   <aop:pointcut id="txPoint" expression="execution(* com.stujc.mapper.*.*(..))"/>
   <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
 
posted @ 2024-06-25 15:18  孟秋廿六  阅读(8)  评论(0)    收藏  举报