vlambda博客
学习文章列表

Spring5知识点简要梳理

IOC-XML

创建对象

 <bean id="book" class="bean.Book"></bean>
  • 在spring配置文件中,使用bean标签,在标签中添加对应属性,就可以实现对象创建

  • bean标签中的属性

    • id属性:相当于给类起别名,作为唯一标识

    • class属性:要创建的对象所属类的全路径(包路径)

    • name属性(不用):等同于id,区别在于name中可以加特殊符号

  • 创建对象的时候,默认执行无参构造方法

注入属性

使用set方法注入(需要生成对应set方法)

 <!--配置对象的创建,使用set方法注入属性-->
 <bean id="book" class="bean.Book">
     <!--使用property完成属性注入
         name:类里面的属性名称
         value:向属性注入的值
     -->
     <property name="name" value="时间简史"></property>
     <property name="author" value="霍金"></property>
 </bean>

使用有参构造方法注入(需要生成对应有参构造方法)

 <!--方式一:配置对象的创建,使用有参构造方法注入属性-->
 <bean id="order" class="bean.Order">
     <constructor-arg name="name" value="时间简史"/>
     <constructor-arg name="address" value="二仙桥"/>
 </bean>
 
 <!--方式二:配置对象的创建,使用有参构造方法注入属性-->
 <bean id="order" class="bean.Order">
  <constructor-arg index="0" value="时间简史"/>
  <constructor-arg index="1" value="二仙桥"/>
 </bean>

p名称空间注入(简化使用set方法注入)

 <!--在beans标签中添加属性xmlns:p-->
 xmlns:p="http://www.springframework.org/schema/p"
 <!--set方法注入属性-->
 <bean id="book" class="bean.Book" p:name="时间简史" p:author="霍金"></bean>

特殊属性注入

空值与特殊符号

 <bean id="book" class="bean.Book">
     <!--向属性中设置null值-->
     <property name="name">
         <null></null>
     </property>
     <!--属性值中包含特殊符号
         方式一:使用转义
         方式二:使用CDATA,<![CDATA[具体内容]]>
     -->
     <property name="author">
         <value><![CDATA[<<霍金>>]]></value>
     </property>
 </bean>

bean注入(假设Employee中有Department类型属性dep)

 <!--方式一-->
 <bean id="dep" class="bean.Department">
     <property name="dep.name" value="行政部"></property>
 </bean>
 <bean id="emp" class="bean.Employee">
     <!--注入userDao对象
         name:类里属性的名称
         ref:dep属性(对象)的id值
     -->
     <property name="dep" ref="dep"></property>
 </bean>
 
 <!--方式二-->
 <bean id="emp" class="bean.Employee">
     <!--设置普通属性-->
     <property name="name" value="Tom"></property>
     <!--设置对象属性-->
     <property name="dep">
         <bean id="dep" class="bean.Department">
             <property name="name" value="技术部"></property>
         </bean>
     </property>
 </bean>
 
 <!--方式三-->
 <bean id="dep" class="bean.Department"></bean>
 <bean id="emp" class="bean.Employee">
     <!--设置普通属性值-->
     <property name="name" value="Tom"></property>
     <!--要先在Employee类中生成dep属性的get方法!!!-->
     <property name="dep" ref="dep"></property>
     <property name="dep.name" value="行政部"></property>
 </bean>
 
 <!--方式四-->
 <bean id="dep" class="bean.Department" >
     <property name="dep.name" value="行政部"></property>
 </bean>
 <bean id="emp" class="bean.Employee" autowire="byName"></bean>
 <!--相当于在emp的bean标签中省去<property name="dep" ref="dep"></property>-->

集合属性

 <!--集合类型属性注入-->
 <bean id="stu" class="collection.Student">
     <!--数组类型属性注入-->
     <property name="arr">
         <array>
             <value>javaEE基础</value>
             <value>数据库</value>
         </array>
     </property>
 
     <!--list类型属性注入-->
     <property name="list">
         <list>
             <value>Tom</value>
             <value>Bob</value>
         </list>
     </property>
 
     <!--map类型属性注入-->
     <property name="map">
         <map>
             <entry key="key1" value="value1"></entry>
             <entry key="key2" value="value2"></entry>
         </map>
     </property>
 
     <!--set类型属性注入-->
     <property name="set">
         <set>
             <value>MySQL</value>
             <value>Redis</value>
         </set>
     </property>
 </bean>

(1)在集合中设置对象类型值

 <bean id="stu" class="collection.Student">
     <!--List集合类型属性注入,值为对象-->
     <property name="courseList">
         <list>
             <ref bean="course1"></ref>
             <ref bean="course2"></ref>
         </list>
     </property>
 </bean>
 <!--创建多个course对象-->
 <bean id="course1" class="collection.Course">
     <property name="name" value="Spring5框架"></property>
 </bean>
 <bean id="course2" class="collection.Course">
     <property name="name" value="MyBatis框架"></property>
 </bean>

(2)把集合注入部分提取出来:在Spring配置文件中引入名称空间util,使用util标签完成list集合注入提取

 <!--提取list集合类型属性注入-->
 <util:list id="bookList">
     <value>数据结构与算法</value>
     <value>计算机组成原理</value>
 </util:list>
 <!--提取list集合类型属性注入的使用-->
 <bean id="book" class="collection.Bookshelf">
     <property name="bookList" ref="bookList"></property>
 </bean>

IOC-注解

创建对象

 <!--第一步:引入名称空间context-->
 <!--第二步:开启组件扫描-->
 <!--多个包用逗号隔开-->
 <context:component-scan base-package="annotation.dao,annotation.service"></context:component-scan>
 <!--扫描目录下所有包-->
 <context:component-scan base-package="annotation"></context:component-scan>
 
 <!--use-default-filters="false"表示现在不使用默认filter,自己配置filter
  子标签:
  context:include-filter,设置需要扫描的内容
     context:exclude-filter,设置不需要扫描的内容
  type:扫描依据
  annotation:根据注解进行扫描
 -->
 /**
  * 注解里面的value属性可以省略不写,默认是首字母小写的类名
  * 四个注解:@Component、@Service、@Controller、@Repository,只存在语义上的区别
  */
 @Component(value = "userService")
 public class UserService {
     public void add(){
         System.out.println("package service.UserService");
    }
 }

注入属性

 /**
  * @AutoWired,根据属性类型进行注入
  * @Qualider,根据属性名称进行注入,@Qualider和@AutoWired搭配使用
  * @Resource,可以根据类型注入,也可以根据名称注入,位于拓展包javax中
  * @Value,注入普通类型属性
  */
 @Service
 public class ManagerService {
 
     /**
      * 不需要添加set方法,只需添加注入属性注解
      * value指定要注入的值,对于@Qualifier,值指具体实现类,对@Value,值指具体值
      */
     @Autowired
     @Qualifier(value = "managerDaoImpl")
     private ManagerDao managerDao;
     
     @Value(value = "root")
  private String name;
 
     public void login(){
         managerDao.search();
         System.out.println("登陆成功");
    }
 }

纯注解

创建配置类,替代xml配置文件,使用时改用AnnotationConfigApplicationContext()方法

 @Configuration  //作为配置类,替代xml配置文件
 @ComponentScan(basePackages = {"annotation"})   //<!--开启组件扫描-->
 public class SpringConfig {
 
 }
 public void test(){
         ApplicationContext context=new AnnotationConfigApplicationContext("annotation.config");
         ManagerService managerService = context.getBean("managerService", ManagerService.class);
         managerService.login();
    }


Bean的生命周期

生命周期:从对象创建到对象销毁的过程

(1)通过构造器创建bean实例(执行无参构造方法)

(2)为bean的属性设置值和对其它bean的引用(调用set方法)

(2.5)把bean实例传递给bean的后置处理器方法

(3)调用bean的初始化方法(需要配置)

(3.5)把bean实例传递给bean的后置处理器方法

(4)使用bean

(5)当容器关闭的时候,调用bean的销毁方法(需要配置)

 public class food {
     private String name;
 
     public food() {
         System.out.println("1.执行无参构造创建bean实例");
    }
 
     public void setName(String name) {
         this.name = name;
         System.out.println("2.执行set方法完成属性设置");
    }
 
     //初始化方法的方法名自己定,写完初始化方法后到xml中配置初始化方法
     public void init(){
         System.out.println("3.执行初始化方法");
    }
 
     //销毁方法的方法名自己定,写完初始化方法后到xml中配置初始化方法
     public void destroy(){
         System.out.println("5.执行销毁方法");
    }
 }
 <!--init-method属性配置初始化方法
     destroy-method属性配置销毁方法
 -->
 <bean id="food" class="lifecycle.food" init-method="init" destroy-method="destroy">
     <property name="name" value="宫保鸡丁"></property>
 </bean>
 public class FoodTest {
     @Test
     public void test(){
         ApplicationContext context=new ClassPathXmlApplicationContext("food.xml");
         food food = context.getBean("food", food.class);
         System.out.println("4.获取到bean对象并使用");
         System.out.println(food);
 
         //手动销毁bean实例
        ((ClassPathXmlApplicationContext)context).close();
    }
 }

AOP-JDK

 public class JDKProxy {
     public static void main(String[] args) {
 
         /**
          * 创建接口实现类代理对象
          * newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
          * 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序
          * loader:类加载器
          * interfaces:增强方法所在的类实现的接口
          * h:实现接口InvocationHandler,创建代理对象,写增强的部分
          */
         Class[] interfaces={UserDao.class};
         InvocationHandler h=new UserDaoProxy(new UserDaoImpl())
         //接口等于实现类的代理对象
         UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, h);
         int add = dao.add(1, 2);
         System.out.println("结果为:"+add);
    }
 }
 
 //创建代理对象代码
 class UserDaoProxy implements InvocationHandler{
 
     //创建的是谁的代理对象,就把谁传递过来
     //有参构造传递
     private Object obj;
 
     public UserDaoProxy() {
    }
 
     public UserDaoProxy(Object obj){
         this.obj=obj;
    }
 
     //增强的逻辑
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
         //方法之前
         System.out.println("方法之前执行:"+method.getName()+"传递的参数:"+ Arrays.toString(args));
         //方法执行
         Object res = method.invoke(obj, args);
         //方法之后
         System.out.println("方法之后执行:"+obj);
         return res;
    }
 }

AOP-CGLIB


基于xml

 public class Book {
     public void buy(){
         System.out.println("Book中的buy");
    }
 }
 public class BookProxy {
     private void before(){
         System.out.println("before前置通知");
    }
 }
 <!--创建对象-->
 <bean id="book" class="bean.Book"></bean>
 <bean id="bookProxy" class="bean.BookProxy"></bean>
 
 <!--配置aop增强-->
 <aop:config>
     <!--切入点-->
     <aop:pointcut id="point" expression="execution(* bean.Book.buy(..))"/>
     <!--配置切面-->
     <aop:aspect ref="bookProxy">
         <!--用before()方法来增强指定的buy()方法-->
         <aop:before method="before" pointcut-ref="point"></aop:before>
     </aop:aspect>
 </aop:config>

基于注解

 @Component
 public class Manager {
     public void add(){
         System.out.println("Manager中的add操作");
    }
 }
 <!--引入名称空间context与aop-->
 <!--开启注解扫描-->
 <context:component-scan base-package="bean"></context:component-scan>
 <!--开启Aspectj生成代理对象-->
 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 /* 创建增强类,编写增强逻辑*/
 @Component
 @Aspect //生成代理对象
 public class ManagerProxy {
     //在增强类里面,创建方法,让不同方法代表不同通知类型
 
     //前置通知
     // @Before表示作为前置通知
     @Before(value = "execution(* bean.Manager.add())") //org.aspectj.lang.annotation.Before
     public void before(){
         System.out.println("before前置通知");
    }
 
     //后置通知(返回通知),@AfterReturning在方法返回结果之后执行,有异常时不执行
     @AfterReturning(value = "execution(* bean.Manager.add())")
     public void afterReturning(){
         System.out.println("afterReturning通知");
    }
 
     //异常通知
     @AfterThrowing(value = "execution(* bean.Manager.add())")
     public void afterThrowing(){
         System.out.println("afterThrowing异常通知");
    }
 
     //环绕通知
     @Around(value = "execution(* bean.Manager.add())")
     public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
         System.out.println("around环绕通知(环绕之前)"); // 最先执行
         proceedingJoinPoint.proceed(); // 被增强的方法执行
         System.out.println("around环绕通知(环绕之后)"); // 紧跟被增强的方法
    }
 
     //最终通知,@After在方法结束后执行,无论方法是否存在异常
     @After(value = "execution(* bean.Manager.add())")
     public void after(){
         System.out.println("after后置通知");
    }
 }
 /**
  * 相同切入点抽取
  * 此时pointCut()就可以替代通知中value中的值execution(* bean.Manager.add())
  */
 @Pointcut(value ="execution(* bean.Manager.add())")
 public void pointCut(){
 }
 
 /**
  *多个增强类对同一个方法进行增强时,设置增强类的优先级,默认2147483647
  */
 @Component
 @Aspect
 @Order(1)   //@Order(1)设置增强类的优先级,数字越小,优先级越高
 public class BossProxy {
     @Before(value = "pointCut()")
     public void before(){
         System.out.println("Boss中的before前置通知");
    }
 }

纯注解

 @Configuration  //作为配置类,替代xml配置文件
 @ComponentScan(basePackages = {"bean"})   // 开启组件扫描
 @EnableAspectAutoProxy(proxyTargetClass=true) // 开启Aspectj生成代理对象,默认false
 public class SpringConfig {
 
 }

JdbcTemplate


Spring框架对JDBC进行封装,使用JDBCTemplate方便实现对数据库操作

相关配置

jdbc.properties配置文件

 driverClassName=com.mysql.cj.jdbc.Driver
 url=jdbc:mysql://localhost:3306/spring
 username=root
 password=byte1024
 <!--开启组件扫描-->
 <context:component-scan base-package="dao"></context:component-scan>
 
 <!--引入外部文件-->
 <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
 <!--配置连接池-->
 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
     <property name="driverClassName" value="${driverClassName}"></property>
     <property name="url" value="${url}"></property>
     <property name="username" value="${username}"></property>
     <property name="password" value="${password}"></property>
 </bean>
 <!--JdbcTemplate对象-->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
     <!--注入DataSource-->
     <property name="dataSource" ref="dataSource"></property>
 </bean>
 public interface BookDao {
 }
 
 @Repository
 public class BookDaoImpl implements BookDao{
 
     //注入JdbcTemplate
     @Autowired
     private JdbcTemplate jdbcTemplate;
 }
 @Service
 public class BookService {
     //注入dao
     @Autowired
     private BookDao bookDao;
 }

操作数据库

 @Override
 public void addBook(Book book) {
     String sql="insert into `book` values(?,?,?)";
     int update = jdbcTemplate.update(sql, book.getId(), book.getName());
 }
 
 @Override
 public void batchAddBook(List<Object[]> lists) {
     String sql="insert into `book` values(?,?)";
     int[] ints = jdbcTemplate.batchUpdate(sql, lists);
 }
 
 @Override
 public void updateBook(Book book) {
     String sql="update `book` set `name`=? where id=?";
     int update = jdbcTemplate.update(sql, book.getName(), book.getId());
 }
 
 @Override
 public void batchUpdateBook(List<Object[]> lists) {
     String sql="update `book` set `name`=? where id=?";
     int[] ints = jdbcTemplate.batchUpdate(sql, lists);
 }
 
 @Override
 public void deleteBook(String id) {
     String sql="delete from `book` where id=?";
     int update = jdbcTemplate.update(sql, id);
 }
 
 @Override
 public void batchDeleteBook(List<Object[]> lists) {
     String sql="delete from `book` where id=?";
     int[] ints = jdbcTemplate.batchUpdate(sql, lists);
 }
 
 @Override
 public int queryCount() {
     String sql="select count(*) from `book` ";
     Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
     return count;
 }
 
 @Override
 public Book queryBook(String id) {
     String sql="select * from `book` where `id`=?";
     Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Book.class), id);
     return book;
 }
 
 @Override
 public List<Book> queryBooks() {
     String sql="select * from `book`";
     List<Book> books = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Book.class));
     return books;
 }

事务管理

基于注解

 <!--先引入名称空间tx-->
 <!--开启事务注解-->
 <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
 
 <!--配置连接池-->
 <!--JdbcTemplate对象-->
 <!--创建事务管理器-->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <!--注入数据源-->
     <property name="dataSource" ref="dataSource"></property>
 </bean>

在service类上面(或service类里面的方法上面)添加事务注解@Transactional。添加到类上相当于给类中所有方法添加了事务注解,添加到方法上面只是给特定方法添加事务注解

 // @Transactional参数配置
 /**
  * propagation:事务传播行为
  * 多事务方法直接进行调用,这个过程事务是如何进行管理的
  * 事务方法:对数据库表数据进行变化的操作(增删改)
  */
 @Transactional(propagation = Propagation.REQUIRED)
 
 /*isolation:事务隔离级别*/
 @Transactional(isolation = Isolation.REPEATABLE_READ)
 
 /**
  * timeout:超过时间
  * 事务需要在一定时间内进行提交,如果不提交,会进行回滚
  * 默认值为-1,设置时间以秒为单位
  */
 
 /**
  * readOnly:是否只读
  * 读:查询操作,写:增删改操作
  * 默认值为false,表示可读可写,当设置true时,只能读
  */
 
 /**
  * rollbackFor:回滚
  * 设置出现哪些异常进行事务回滚
  */
 
 /**
  * noRollbackFor:不回滚
  * 设置出现哪些异常不进行事务回滚
 */
事务的传播行为 说明
REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值
REQUIRES_NEW 创建一个新的事务,如果当前存在事务,则把当前事务挂起
SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起
NEVER 以非事务方式运行,如果当前存在事务,则抛出异常
MANDATORY 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于REQUIRED

基于xml

 <!--先引入名称空间tx-->
 <!--开启事务注解-->
 <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
 
 <!--配置连接池-->
 <!--JdbcTemplate对象-->
 <!--创建事务管理器-->
 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <!--注入数据源-->
     <property name="dataSource" ref="dataSource"></property>
 </bean>
 
 <!--配置通知-->
 <tx:advice id="advice">
     <!--配置事务参数-->
     <tx:attributes>
         <!--指定哪种规则的方法上面添加事务
  name:方法名字,可正则
  -->
         <tx:method name="transferAccount" propagation="REQUIRED"/>
     </tx:attributes>
 </tx:advice>
 <!--配置切入点和切面-->
 <aop:config>
     <!--配置切入点-->
     <aop:pointcut id="point" expression="execution(* service.UserService.*(..))"/>
     <!--配置切面(将事务和方法相关联)-->
     <aop:advisor advice-ref="advice" pointcut-ref="point"></aop:advisor>
 </aop:config>

纯注解

 @Configuration  //配置类
 @ComponentScan(basePackages = {"service","dao"} )   //开启组件扫描
 @EnableTransactionManagement    //开启事务
 public class TxConfig {
 
     //创建数据库连接池
     @Bean
     public DruidDataSource getDruidDataSource(){
         DruidDataSource druidDataSource = new DruidDataSource();
 
         druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
         druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring5");
         druidDataSource.setUsername("root");
         druidDataSource.setPassword("byte1024");
 
         return druidDataSource;
    }
 
     //创建JdbcTemplate对象
     @Bean
     public JdbcTemplate getJdbcTemplate(DataSource dataSource){
         JdbcTemplate jdbcTemplate = new JdbcTemplate();
         //到IOC容器中根据类型找到dataSource
         //注入dataSource
         jdbcTemplate.setDataSource(dataSource);
 
         return jdbcTemplate;
    }
 
     //创建事务管理
     @Bean
     public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
         DataSourceTransactionManager transactionManager=new DataSourceTransactionManager(dataSource);
         return transactionManager;
    }
 
 }