Spring框架概念+实战

1.依赖注入

依赖:就是一种关系,代表了软件实体之间的联系。以表明一个软件实体,依靠另一个软件实体的规范或实现,而不能自立或自给。

原本是这么写的,耦合度太高

包结构

Spring框架概念+实战_第1张图片

dao包下

UserDao
package com.example.dao;

import com.example.entity.User;

public interface UserDao {
    User selectUserById(Long id);

}

UserDaoImpl
package com.example.dao;

import com.example.entity.User;

public class UserDaoImpl implements UserDao {
    @Override
    public User selectUserById(Long id) {
        System.out.println("UserDaoImpl.selectUserById");
        return null;
    }
}

service包下

UserService
package com.example.service;

import com.example.entity.User;

public interface UserService {
    User findUserById(Long id);
}
UserServiceImpl
package com.example.service;

import com.example.dao.UserDao;
import com.example.entity.User;

public class UserServiceImpl implements UserService {
    UserDao userDao = new UserDaoImpl();

    @Override
    public User findUserById(Long id) {
        return userDao.selectUserById(id);
    }
}

entity包

User
package com.example.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String password;
}

Test包下

UserServiceImplTest
package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImplTest extends TestCase {
    UserService userService = new UserServiceImpl();
    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

运行效果

Spring框架概念+实战_第2张图片

纯xml方式

1.添加jar包

    
      org.springframework
      spring-context
      ${Spring.version}
    

2.创建配置文件applicationContext.xml




    
    
    

    
        
        
    

applicationContext.xml文件中标签的属性不自动提示

创建两个Bean,userService中引用了userDao,所以多添加一个属性,表示引用关系

容器获取的Bean默认是单例模式,通过scope属性设置

Spring容器创建bean的使用调用的是类的空参构造

3.在使用时,如在Test中

(1)实例化容器对象

(2)从容器中获取Bean实例

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImplTest extends TestCase {
    UserService userService ;
    @Test
    public void testFindUserById() {
        //1.实例化容器对象
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从容器中获取Bean实例
        UserService userService=(UserService) ac.getBean("userService");
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

这里需要注意的是,这是使用set方式注入

所以要在实现类中添加set方法

package com.example.service;

import com.example.dao.UserDao;
import com.example.entity.User;

public class UserServiceImpl implements UserService {
    UserDao userDao ;
    // xml方式需要提供属性的set方法来绑定

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public User findUserById(Long id) {
        return userDao.selectUserById(id);
    }
}

通过构造器的方式注入

XML+注解(annotation)

1.在相应的位置添加注解

1、@controller 控制器(注入服务)
2、@service 服务(注入dao)
3、@repository dao(实现dao访问)
4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的)@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。 
下面写这个是引入component的扫描组件 
   

2.修改配置文件applicationContext.xml




        
    

可以扫描com.example下所有带注解的部分

3.修改测试调用

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//使用spring-test测试,导入相应的包
//加载主配置文件
@ContextConfiguration("classpath:applicationContext.xml")
//使用spring的测试
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

导入spring-test包

    
      org.springframework
      spring-test
      ${Spring.version}
    

已经导入Spring-context包但是没有出现注解

解决办法:清一下idea的缓存

Spring框架概念+实战_第3张图片

java.lang.IllegalStateException: SpringJUnit4ClassRunner requires JUnit 4.12 or higher.

解决办法:

JUnit需要更高版本

    
      junit
      junit
      4.12
      test
    

运行结果:Spring框架概念+实战_第4张图片

纯注解方式

1.添加配置类AppConfig

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;

/*
 * Spring 主配置类
 * */
//表示该类是一个spring核心配置类
@ContextConfiguration
//表示扫描包
//注意:可以通过basepackage配置扫描路径,如果不写,默认扫描该类所在的包以及子包
@ComponentScan
public class AppConfig {
}

2.修改测试类参数

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//使用spring-test测试,导入相应的包
@ContextConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

运行结果:

Spring框架概念+实战_第5张图片

添加一个list测试

AppConfig

package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.event.annotation.BeforeTestExecution;

import java.util.ArrayList;
import java.util.List;

/*
 * Spring 主配置类
 * */
//表示该类是一个spring核心配置类
@ContextConfiguration
//表示扫描包
//注意:可以通过basepackage配置扫描路径,如果不写,默认扫描该类所在的包以及子包
@ComponentScan
public class AppConfig {
    
    @Bean
    public List list() {
        List list = new ArrayList<>();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        return list;
    }
}

测试类

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

//使用spring-test测试,导入相应的包
@ContextConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Autowired
    List list;
    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }

    @Test
    public void listTest(){
        list.forEach(System.out::println);
    }
}

运行结果

Spring框架概念+实战_第6张图片

2.AOP面向切面编程

目的是为了更高效的代码复用

问题有很多方法的时候,实现类需要重复写非核心代码

Spring框架概念+实战_第7张图片

Spring框架概念+实战_第8张图片

Execution

Spring框架概念+实战_第9张图片

XML方式

1.添加包

   
      org.springframework
      spring-aspects
      ${Spring.version}
    

2.创建通知类,共性逻辑代码

package com.example.advice;

import org.aspectj.lang.JoinPoint;

import java.util.Date;

/*
* Advice通知
* */
public class LogAdvice {
    //jp对象是现场信息的封装
    public void log(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
    }
}
package com.example.advice;

import org.aspectj.lang.JoinPoint;

import java.util.Date;

/*
 * Advice通知
 * */
public class PermissionAdvice {
    public void check(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
    }
}

3.修改配置文件




    
    

    
        
        
    

    
    
    

    
    
        
            
            
        
    


特别注意execution表达式,非常灵活,指定哪些方法切入

上述代码达到的目的就是,在方法中没有写权限验证的代码但是,执行的时候依然会执行,就是因为AOP切到这个方法之前执行了

Spring框架概念+实战_第10张图片

运行结果

Spring框架概念+实战_第11张图片

XML+注解

主要是advice添加注解

1.对应位置添加注解

UserDaoImpl @Repository
UserServiceImpl @Service
LogAdvice 
package com.example.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Date;

/*
* Advice通知
* */
@Component
//注解配置切面
@Aspect
public class LogAdvice {
    //jp对象是现场信息的封装
    @After("execution(* com.example..*ServiceImpl.find*(..))")
    public void log(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
        System.out.println("日志记录");
    }
}
PermissionAdvice
package com.example.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Date;

/*
 * Advice通知
 * */
@Component
@Aspect
public class PermissionAdvice {
    @Before("execution(* com.example..*ServiceImpl.find*(..))")
    public void check(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
        System.out.println("权限验证中...");
    }
}

2.修改配置文件




    
    
    
    


3.修改测试文件

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    @Autowired
    UserService userService;

    @Test
    public void testFindUserById() {
        User user = userService.findById(1L);
        System.out.println(user);
    }
}

运行结果

Spring框架概念+实战_第12张图片

纯注解方式

1.添加主配置类

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.test.context.ContextConfiguration;
//spring主配置文件类
@ContextConfiguration
//扫描注解
@ComponentScan
//开启AOP
@EnableAspectJAutoProxy
public class AppConfig {
}

2.修改测试类

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(classes= AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    @Autowired
    UserService userService;

    @Test
    public void testFindUserById() {
        User user = userService.findById(1L);
        System.out.println(user);
    }
}

运行结果

Spring框架概念+实战_第13张图片

 

3.声明式事务

事务四大特性:ACID

编程式事务:代码写死事务边界

声明式事务:动态确定事务边界

Propagation(传播行为)

被定义了声明式事务的方法,有权知道当前是否有事务开启,并有权决定是否加入当前事务。某个方法增加到当前事务,相当于事务被传播了。传播的实质,也就是对事务的边界,在程序运行期间动态地进行控制。

Spring框架概念+实战_第14张图片

配置声明式事务管理器

spring由于需要为多种数据层的实现提供集成支持,针对不同的情况,定义了各种事务管理器,一定要选择正确的事务管理器

如:对应JDBC事务,对应Hibernate提供的事务,对应JTA事务

备注:大多数事务管理器需要设置dataSource属性或sessionFactory属性

 

你可能感兴趣的:(java)