Spring IOC 和Spring AOP

Spring IOC

控制翻转和依赖注入在Spring环境下是等同的概念,控制翻转是通过依赖注入实现的。依赖注入指的是容器负责创建对象和维护对象之间的依赖关系,而不是对象本身自己负责创建和解决自己的依赖。

依赖注入的主要目的是为了解耦,体现了一种“组合”的理念。如果你希望某各类具备某项功能,肯定继承一个具有该功能的父类不如组合一个具有此功能的类,组合一个类降低了耦合度。

Spring IOC容器即ApplicationContext负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中,Spring提供了xml、注解、java配置和groovy配置实现Bean的创建和注入。

声明Bean的注解有:

@Component组件,没有明确的角色

@Service在业务逻辑层使用

@Repository在数据访问层使用

@Controller在展现层使用

注入Bean的注解有:

@Autowired:Spring提供的注解

@Inject:JSR-330提供的注解

@Resource:JSR-250提供的注解

注入Bean的注解可注解在set方法上,也可在属性上

@ComponentScan,扫描定义的包名下所有使用@Service、@Component、@Repository和@Controller的类,并注册为Bean

java配置

public class FunctionService {

    public String sayHelloWorld(String word){
       return "hello " + word + "!";
    }
}



public class UserFunctionService {

    FunctionService functionService;

    public void setFunctionService(FunctionService functionService) {
        this.functionService = functionService;
    }

    public String sayHelloWorld(String word){
        return functionService.sayHelloWorld(word);
    }
}




@Configuration
public class JavaConfig {

    @Bean
    public FunctionService functionService(){
        return new FunctionService();
    }

    @Bean
    public UserFunctionService userFunctionService(){
        UserFunctionService userFunctionService = new UserFunctionService();
        userFunctionService.setFunctionService(functionService());
        return userFunctionService;
    }
}





public class Main {

    public  static void main(String[] args){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);
        UserFunctionService userFunctionService = applicationContext.getBean(UserFunctionService.class);
        System.out.println(userFunctionService.sayHelloWorld("hello config"));
        applicationContext.close();
    }
}

执行结果:

@Configuration声明当前类是一个配置类,意味着这个类中有0个或者多个注解,相当于Spring中配置的xml文件

@Bean 注解在方法上,声明当前方法的返回值为一个Bean,Bean的名称为方法名

Spring AOP

Spring的aop的存在目的是为了解耦。aop可以让一组类共享相同的行为。

@Aspect声明一个切面

@After、@Before、@AfterThrowing、@AfterRunning、@Around定义建言,可直接将拦截规则作为参数

@After:在目标方法完成之后做增强

@Before:在目标方法被调用之前做增强处理

@AfterThrowing:主要处理程序中未处理的异常,@AfterThrowing(pointcut = "切点", throwing = "e")可以指定一个throwing的返回值形参名,通过该形参名来访问目标方法中所抛出的异常对象。

@AfterReturning:在目标方法完成之后做增强,除了指定切入点表达式,还可以指定一个返回值形参名returring,代表目标方法的返回值。

 @AfterReturning(pointcut = "execution(* com.test.aop.*.*(..))", returning = "result")
    public void afterRunning(JoinPoint joinPoint, Object result){
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        System.out.println("方法规则式拦截" + method.getName());
        System.out.println("返回结果" + result);
    }

@Around:环绕通知,在目标方法完成前后做增强处理,像事务、日志等都是环绕通知,它的编程核心是ProceedingJoinPoint

eg:基于注解拦截和基于方法规则拦截

//拦截规则的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
   String name();
}

注解说明:元注解是指注解的注解,包括@Target、@Retention、@Document、@Inherited四种
@Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在与源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)  //默认的保留策略,注解在class字节码文件中存在,但在运行中无法获得
@Retention(RetentionPolicy.RUNTIME) //注解在class字节码文件中存在,在运行时可以通过反射获取到

首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。

@Target:定义注解的作用目标
@Target(ElementType.TYPE)  //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR)  //构造函数
@Target(ElementType.LOCAL_VARIABLE)  //局部变量
@Target(ElementType.ANNOTATION_TYPE) //注解
@Target(ElementType.PACKAGE)  //包

@Document:说明该注解将包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解


//使用注解和方法规则的被拦截类
@Service
public class AnnotationService {

    @Action(name = "注解式拦截的add操作")
    public void add(){}

    public void delete(){}
}


//使用方法规则的被拦截类
@Service
public class MethodService {

    public void add(){}

    public int delete(){ return 2;}
}



//编写切面
@Aspect     //使用@Aspect注解声明一个切面
@Component   //使用@Component让该切面成为Spring容器管理的Bean
public class LogAspect {

    @Pointcut("@annotation(com.test.aop.Action)")  //@Pointcut注解声明切点
    public void annotationPointCut(){};

    @After("annotationPointCut()")   //@After注解声明一个建言
    public void after(JoinPoint joinPoint){
        MethodSignature  methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Action action = method.getAnnotation(Action.class);
        System.out.println("注解式拦截" + action.name());
    }

    @AfterReturning(pointcut = "execution(* com.test.aop.*.*(..))", returning = "result")
    public void afterRunning(JoinPoint joinPoint, Object result){
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        System.out.println("方法规则式拦截" + method.getName());
        System.out.println("返回结果" + result);
    }
}




@Configuration    //声明该类为配置类
@EnableAspectJAutoProxy    //使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持
@ComponentScan("com.test.aop")
public class AopConfig {
}




public class Main {

    public static void main(String[] args){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
        AnnotationService annotationService = applicationContext.getBean(AnnotationService.class);
        MethodService methodService = applicationContext.getBean(MethodService.class);
        annotationService.add();
        annotationService.delete();
        methodService.add();
        methodService.delete();
        applicationContext.close();
    }
}

返回结果:

猜你喜欢

转载自blog.csdn.net/m0_37637141/article/details/86591215