• spring之ioc及aop编程


    1.spring的jar包下载

    2.在src下新建一个文件夹resources,放个配置文件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"
    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/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 扫描注解类 -->
    <context:component-scan base-package="tcc"></context:component-scan>
    <!-- <context:component-scan base-package="tcc.test.springioc"></context:component-scan> -->

    <!-- 确定 AOP注解生效 -->
    <!-- <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,
    当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。
    不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。 -->

    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
    </beans>

    3.写个ioc测试类

    package tcc.test.springioc;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class Test {

    @SuppressWarnings("resource") //抑制警告,打断点不影响
    public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
    Student student = ac.getBean("student", Student.class);
    student.eat();
    }

    }

    测试bean

    package tcc.test.springioc;

    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;

    @Scope("prototype")

    //singleton 表示在spring容器中的单例,通过spring容器获得该bean时总是返回唯一的实例
    //prototype表示每次获得bean都会生成一个新的对象
    //request表示在一次http请求内有效(只适用于web应用)
    //session表示在一个用户会话内有效(只适用于web应用)
    //globalSession表示在全局会话内有效(只适用于web应用)
    //在多数情况,我们只会使用singleton和prototype两种scope,如果在spring配置文件内未指定scope属性,默认为singleton。

    @Component("student")//类注解
    public class Student {
    public void eat(){
    System.out.println("Student类新增了");
    }

    }

    SpringIOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入

    BeanFactoryApplicationContext有什么区别?

            BeanFactoryApplicationContextSpring的两大核心接口,都可以当做Spring的容器。其中ApplicationContextBeanFactory的子接口。

    1BeanFactorySpring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能

    2)①BeanFactroy采用的是延迟加载形式来注入Bean,即只有在使用到某个Bean(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

      ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误

    BeanFactory需要手动注册,而ApplicationContext则是自动注册。

    Spring框架中的单例Beans是线程安全的么?

       Spring框架并没有对单例bean进行任何多线程的封装处理。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

    9Spring如何处理线程并发问题?

    在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题

    ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

    ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal

    创建对象的时机

              1、在默认的情况下,通过xml配置的在spring容器启动的时候创建对象

                       在spring配置文件中,只要根据以上的三种方式的其中一种配置了,spring容器就会创建对象

                       好处:spring容器和web容器整合的时候,当web容器启动的时候就可以初始化spring容器了,如果这个时候

                               spring容器内部有错误,则直接会报错

                       如果该bean中存放着大量的数据,而且数据的初始化发生在创建对象的时候,这个时候,数据会过早的驻留在内存中

              2、如果在spring的配置文件中一个bean的配置中有lazy-init="true",那么该bean在调用getBean方法时创建对象

                       不好处:不能过早的发现错误

                       好处:按照需求加载数据(什么时候要什么时候加载)

    <bean id="ms1" class="basic.MassageService" init-method="in" destroy-method="des"/>

    各种对象,都是在tomcat启动时创建,Tomcat怎么知道的?
    tomcat启动时  会把每一个项目的所有代码扫描一遍,需要它启动时就创建的,就创建对象。

    Tomcat在启动时都创建了哪些对象?慢慢总结如下:
    servletContext(一个项目的全局变量)、Servlet(load-on-startup为非负数时)、Filter(整个项目的过滤器)

    写个aop测试类

    1.

    package tcc.test.springaop;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class Test {

    @SuppressWarnings("resource")
    public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
    Person person = ac.getBean("person", Person.class);
    person.add();//调用一次MyAspectJ类
    person.update();//调用一次MyAspectJ类
    person.delete();//调用一次MyAspectJ类
    }

    }

    2.

    package tcc.test.springaop;
    public interface Person {

    public void add();
    public void update();
    public void delete();
    }

    3.

    package tcc.test.springaop;

    import javax.annotation.Resource;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import tcc.test.springioc.Student;

    @Component("person")//类注解
    public class PersonImple implements Person {

    /**
    * @desc 实现接口方法
    */

    @Autowired //默认按类型装bai配(这个注解是属业spring的)
    Student student;
    @Resource //这个注解属于J2EE的),默认按照名称进行装配
    Student student2;

    public void add() {
    student2.eat();
    student.eat();
    System.out.println("add()方法执行了.....");//3
    int i = 1/0;
    }

    @Override
    public void update() {
    System.out.println("update()方法执行了.....");
    // int i = 1/0;
    }

    @Override
    public void delete() {
    System.out.println("delete()方法执行了.....");
    }

    }

    4.

    package tcc.test.springaop;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    @Component//类注解
    @Aspect//AspectJ注解
    public class MyAspectJ {

    //声明公共切入点
    @Pointcut("execution(* tcc.test.springaop.PersonImple.*(..))")
    public void myPointcut() {

    }

    //前置通知注解,只有一个参数时,value可以省略不写
    @Before("execution(* tcc.test.springaop.PersonImple.*(..))")
    public void myBefort(JoinPoint joinPoint) {
    System.out.println("前置通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName());//2:会去调用具体的方法
    }

    //后置通知注解,当参数大于1时,value必须写
    @AfterReturning(value="myPointcut()", returning="ret")
    public void myAfterReturning(JoinPoint joinPoint, Object ret) {
    System.out.println("后置通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName()//4
    + ", ret: " + ret);
    }

    //环绕通知注解
    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕通知====前>>>>>>>>>>>");
    Object obj = joinPoint.proceed();//1
    System.out.println("环绕通知====后<<<<<<<<<<<");
    return obj;
    }

    //异常通知注解:出现异常后调用
    @AfterThrowing(value="myPointcut()", throwing="e")
    public void myThrowint(JoinPoint joinPoint, Throwable e) {
    System.out.println("异常通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName() //4
    + ", e: " + e.getMessage());
    System.exit(0);
    }

    //最终通知注解
    @After("myPointcut()")
    public void myAfter(JoinPoint joinPoint) {
    System.out.println("最终通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName());//3
    }
    }

    执行顺序:环绕通知注解@Around("myPointcut()")——》前置通知注解@Before("execution(* tcc.test.springaop.PersonImple.*(..))")——》最终通知注解@After("myPointcut()")——》异常通知注解:出现异常后调用@AfterThrowing(value="myPointcut()", throwing="e")或者后置通知注解@AfterReturning(value="myPointcut()", returning="ret")

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理

            JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和ProxyInvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例生成目标类的代理对象。实现的方式做的动态代理

     如果代理类没有实现 InvocationHandler 接口那么Spring AOP会选择使用CGLIB来动态代理目标类CGLIBCode Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOPCGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

     InvocationHandler invoke(Object  proxy,Method  method,Object[] args)proxy是最终生成的代理实例;  method 是被代理目标实例的某个具体方法;  args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

  • 相关阅读:
    Linux下暴力破解工具Hydra详解
    Github 安全类Repo收集整理
    Linux下显示IP地理位置信息的小工具-nali
    一次渗透小记
    一步随心,一生无悔
    巧遇"drwxr-xr-x."权限
    mysql以ROOT权限提权方法
    HTTP消息中header头部信息的讲解
    浏览器安全-初学篇
    高并发工具推荐
  • 原文地址:https://www.cnblogs.com/tongcc/p/13788737.html
Copyright © 2020-2023  润新知