天天看点

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

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类新增了");

}

Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。

BeanFactory和ApplicationContext有什么区别?

        BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最底层的接口,包含了各种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”。

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

在一般情况下,只有无状态的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;

@SuppressWarnings("resource")

Person person = ac.getBean("person", Person.class);

person.add();//调用一次MyAspectJ类

person.update();//调用一次MyAspectJ类

person.delete();//调用一次MyAspectJ类

2.

public interface Person {

public void add();

public void update();

public void delete();

3.

import javax.annotation.Resource;

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

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;

public void delete() {

System.out.println("delete()方法执行了.....");

4.

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;

@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接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例,  生成目标类的代理对象。实现的方式做的动态代理

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

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

spring之ioc及aop编程