栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

Spring 整体学习(IOC控制翻转 DI依赖注入 AOP 面向切面编程(动态代理) 配置注入 注解注入 )

Java 更新时间:发布时间: 百科书网 趣学号
Spring 一. Spring的IOC与DI

​ IOC(Invertion Of Control)是控制翻转,是一种编程的思想,就是以前在代码中我们需要通过 new 的方式来使用其他的对象,这种方式导致的结果就是类与类之间耦合度过高,耦合度高导致到迭代成本极高;通过控制的翻转的方式,就是我们项目中用到所有的对象,都通用交个一个容器来管理(在spring中我们叫做 IOC容器);
反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)
解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健

​ DI(Dependency Injection)是依赖注入,它是对IOC编程思想的具体实现。在Spring创建对象的同时,为其属性赋值,称之为依赖注入。

1.1 依赖注入

依赖注入主要分为 属性注入(set方法注入) 和 构造器注入

第一步,创建一个配置文件 application-context.xml, 文件内容入如下:



    
    
    
    
    
    
    
  	
    
        
        
        
    
    
    
    
        
        
    

第二步,创建容器,并获取IOC容器中的内容:

IOC容器中的所有bean都会提前创建好,而不是调用的时候再去创建

public class IocTest {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个 IOC 容器
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("meta-INF/application-context.xml");
        // 获取到IOC中的对象
		// Computer c = (Computer)ctx.getBeam("computer");
        
        // 可以根据类型来获取;因为目前对于上面的配置来说,我们有两个 Computer对象,拿到的是 
        // 加了 Primary = true 这个对象
        Computer c = ctx.getBeam(Computer.class);
    }
}
1.2 特殊类型注入

特殊类型指的是:

  1. 引用类型;
  2. List
  3. Map
  4. Set
  5. Propety
  6. 数组

例如给定如下的类:

public class Person {
    private String name;
    private Date birthday;
  	private List dogs
    private List friends;
    private Set account;
    private Map addresses;
    private Properties prop;
    private String[] array;
    // setter and getter
}
public class Dog {
  private String name;
  private Integer age;
}


    
    
    
 	
    	
        
      	
          	
          	
              	
                  	
                  	
              	
              	
                  	
                  	
              	
          	
      	
        
            
        	
            	李四
                王五
            
        
        
        	
        	
            	李四
                王五
            
        
        
        	
        	
            	
                
            
        
         
        	
        	
            	root
                123456
            
        
        
        
        
        	
            	a
                b
                c
            
        
    
 
1.3 自动装配

在 “配置” 的方式上有一个属性 autowire="byName | byType" 两种方式:

  1. byName 是严格按照名字到容器中进行查找,就算有primary="true"也会根据名字找。
  2. byType 是根据属性的类型到容器中进行查找,如果多个会报错,除非在其中一个加上 primary=“true” 这个属性
1.4 单例和非单例模式

在 “配置” 的方式上有一个属性 scope="singleton | prototype" 两种方式创建bean:

  1. singleton 表示从容器中获取的永远是单例的。
  2. prototype表示每次从容器中获取的都是一个新的对象。
二. bean的生命周期

关于 spring中管理的bean的生命周期在spring的一个接口 BeanFactory(是spring容器的顶级接口) 的描述上有准确的描述,但是目前来说,先简单理解 spring 的生命周期:

  1. 实例化,调用构造方法。
  2. 设置属性。
  3. 初始化,调用 init-method(配置的方式) 对应的方法
  4. 创建完毕。
  5. 销毁阶段,调用 destory-method(配置的方式) 对应的方法
public class LifeCycleBean {
    
    private String name;
    
    public void setName(String name) {
        System.out.println("setName 方法被调用了...");
        this.name = name;
    } 
    
    public LifeCycleBean() {
        System.out.println("构造方法被调用了...");
    }
    
    public void init() {
         System.out.println("init 方法被调用了...");
    }
    
    public void destroy() {
        System.out.println("destroy 方法被调用了...");
    }
}


    
    
    
    	
    
 

单例bean:singleton

随工厂启动创建 ==》 构造方法 ==》 set方法(注入值) ==》 init(初始化) ==》 构建完成 ==》随工厂关闭销毁

多例bean:prototype

被使用时创建 ==》 构造方法 ==》 set方法(注入值) ==》 init(初始化) ==》 构建完成 ==》JVM垃圾回收销毁

三. 注入的注解形式开发

spring提供两套创建 IOC 容器的方式:

  1. 配置的方式,这是历史遗留问题。
  2. 注解的方式,这也是未来的主流的方式。(注解创建成员对象的方式是通过构造器)

在三阶段,我们都是混合使用;在四阶段(包括以后工作) 都是适应注解的方式。

@ComponentScan(basePackages = "com.qf")
public class IocTestWithAnnotation {
    public static void main(String[] args) {       
      	
        ApplicationContext ctx = new AnnotationConfigApplicationContext(
            IocTestWithAnnotation.class);
        
        UserService userService = ctx.getBean(UserService.class);

        userService.add();
        userService.delete(45);
        
    }
}

此处注解相当于配置文件中的

@Repository: 这个注解放到 DAO 的实现类上。

@Sercvice: 这个注解放到 Serviece 的实现类上。`

@Component: 性质不明确的时候,就加上该注解。

此处注解相当于配置文件中的autowire="byType | byName "

@Autowired:首先根据类型查找,如果多个,就看谁的头顶的有 @Primary,就注入谁;如果没有没有@Primary 注解,就按照名字来进行注入,如果名字都没有区分就报异常。

@Qualifier: 它的出现就是为了和 @Autowire 搭配使用的,就是指定一个名字,在注入的时候根据类型的时候同时判断名字来实现注入,无视名字和@Primary注解,只根据@Qualifier来创建。

@Resource:首先根据名字来实现注入,如果命名没有相同,就根据类型查找,如果类型有多个,就看谁的大头顶有 @Primary 注解,名字优先于@Primary。

此处的注解相当于init-method | destroy-method配置

@PostConstruct: 对应着 init-method 这个配置的一个注解,是spring bean的生命周期的一个注解。在Spring中碰到方法名或者注解中带有 Post, 表示在XXXX之后。

@PreDestroy: 对应着destroy-method这个配置的一个注解,销毁的时候执行的方法。在Spring中碰到方法名或者注解中带有 Pre, 表示在XXXX之前。

四. AOP

AOP(Aspect Oriented Programming): 面向切面的编程。说白就是可以在方法执行的某个时机做一些其他的工作;他是对应 OOP 的一种增强。AOP底层的实现都是通过动态代理(JDK原生方式和CGLIB的方式)来实现的,在spring框架中,提供了两种实现的方式:

  1. spring原生的方式。(了解即可)
  2. 通过AspectJ框架的方式。

面试: OOP和AOP的区别?

答:OOP面向对象编程,只能通过纵向的添加的代码的方式来实现增强的功能;AOP可以实现在不改变原有方法的代码基础之上实现对方法的横向扩展。

连接点:类中方方法。

切入点:就是我们所关注的方法。

通知:就是当我们所关注的切入点,在发生某个行为的时候,出发某个调用。

4.1 AOP开发术语
  • 连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
  • 切入点(Pointcut):被切入连接点。
  • 通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。
  • 目标对象(Target):代理的目标对象
  • 织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。
  • 代理(Proxy):被AOP织入通知后,产生的结果类。
  • 切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
4.2 通配切入点

根据表达式通配切入点














4.3 AspectJ对于AOP的实现

第一步,创建一个接口,然后定义一个实现类。

public interface StudentService {

    void deleteStudent(Integer id);

    void add();
}
public class StudentServiceImpl implements StudentService {
    public void deleteStudent(Integer id) {
        System.out.println("删除学生:" + id);
    }

    @Override
    public void add() {
        System.out.println("add");
    }
}

第二步,创建一个通知类,类的头顶必须要有 @Aspect 这个注解

@Aspect
public class AopAdvisor {

    
    @Before("execution(* org.example.aop.service.impl.StudentServiceImpl.deleteStudent(..))")
    public void before(JoinPoint jp) {
        System.out.println("UserService下的方法调用之前被执行了...");
        // 获取方法的签名
        MethodSignature signature = (MethodSignature)jp.getSignature();
		//获取方法的对象
        Method method = signature.getMethod();

        System.out.println("方法执行之前打印方法名: " + method.getName());
    }
    
    // 是方法无论正确获取不正确都会执行
    @After("execution(* org.example.aop.service.impl.StudentServiceImpl.add*(..))")
    public void after(JoinPoint jp) {
         System.out.println("方法无论是否抛出异常都会执行");
    }
    
    
    // 方法正确执行了,才会执行该方法
    @AfterReturning("execution(* org.example.aop.service.impl.StudentServiceImpl.add*(..))")
    public void after(JoinPoint jp) {
         System.out.println("方法正确执行了,才会执行该方法");
    }
    
    
     
     @AfterThrowing(value = "execution(* org.example.service.impl.UserServiceImpl.add*(..))", throwing = "npe")
     public void catchSpecifyException(JoinPoint jp, NullPointerException npe) {
         System.out.println("方法抛出了 NPE 异常");
    }
    
     
    @Around("execution(* org.example.service.impl.UserServiceImpl.add*(..))")
    public void around(ProceedingJoinPoint pjp) throws Exception{

      	Object[] args = pjp.getArgs();  // 表示获取方法执行的所有的参数
      	//获取方法的签名
        MethodSignature signature = (MethodSignature)pjp.getSignature();
        //获得当前方法对象
        Method method = signature.getMethod();
        //通过方法获得字节码对象,然后通过字节码对象来获取简单类名
        System.out.println(method.getDeclaringClass().getSimpleName());
      
        Object obj = pjp.proceed(); // 执行目标对象的方法
        
        // 做其他
        return obj;
    }
}

第三步,在配置文件中进行配置




	
    

    

    
    

五. spring与mybatis的整合

第一步,导入依赖:


     
      org.springframework
      spring-context
      5.3.3
    
    
      junit
      junit
      4.13.2
      test
    
    
      org.mybatis
      mybatis
      3.5.7
    
    
      mysql
      mysql-connector-java
      8.0.20
    
    
      com.github.pagehelper
      pagehelper
      5.1.9
    
    
      log4j
      log4j
      1.2.17
    
    
    
      org.mybatis
      mybatis-spring
      2.0.6
    

    
    
      com.zaxxer
      HikariCP
      2.6.1
    

    
      org.springframework
      spring-test
      5.3.3
      test
    

    
      org.springframework
      spring-orm
      5.3.3
    

第二步,配置





    
    

    
    
        
        
        
        
        
        
        
        
    

    
    
        
        
        
        

        
        
            
                
                    
                    
                        
                            
                            mysql
                            
                            true
                        
                    
                
            
        
        
        
            
                
            
        
    

    
    
        
        

        
        
        
    

六. spring的单元测试

第一步,引入依赖:


    org.springframework
    spring-test
    5.3.3
    test

第二部,测试类的编写

@RunWith(SpringJUnit4ClassRunner.class)  // 用于spring测试
@ContextConfiguration("classpath:meta-INF/application-context.xml")
public class UserServiceTest {

    @Autowired
    private IUserService userServiceImpl;

    @Test
    public void getPageData() {
        List list = userServiceImpl.getPageData(2, 10);
        list.forEach(u -> System.out.println(u.getEmail() + "#" + u.getName()));
    }

    @Test
    public void validateTx() {
        userServiceImpl.validateTx();
    }
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/281093.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号