9月15日spring笔记

标签

java

后端

spring

AOP

面向切面编程

注解

代理模式

发布时间:

本文字数:1,236 字 阅读完需:约 5 分钟

利用注解进行Bean的自动扫描管理

使用注解注入可以省略set方法

alt

例子:

spring-scan.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: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/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--    扫描包-->
    <context:component-scan base-package="com.scan"></context:component-scan>
</beans>
  1. 会扫描com.scan包及所有自包下的类
  2. spring会管理如下规则的类

类上加注解:

@Controller (controller层 action)
@Service (service层 model)
@Repository (dao层)
@Component (其他层)

四个注解的区别:

以下注解写在属性之前,见下例
@Value("注入的属性值") :自动根据类型byType注入 @Autowired :自动根据类型byType注入

Computer.java

package com.scan;

import org.springframework.stereotype.Component;

@Component("com")
public class Computer {
    @value("小米")
    private String name;

    // @Resource(name = "intel") //根据name注入,不需Qualifier和Autowired
    @Qualifier("AMD") //过滤名为AMD的CPU的实现类
    @Autowired //自动根据类型byType注入
    private CPU cpu;

    @Override
    public String toString() {
        return "Computer{" +
                "name='" + name + '\'' +
                ", cpu=" + cpu +
                '}';
    }


    
}

TestScan.java

package com.scan;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestScan {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-scan.xml");

        Computer computer = (Computer) ac.getBean("com");

        System.out.println(computer);
    }
}

Intel.java

package com.scan;

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

@Component
public class Intel implements CPU {
    @Value("I9")
    private String name;

    @Override
    public String toString() {
        return "Intel{" +
                "name='" + name + '\'' +
                '}';
    }
}

AMD.java

package com.scan;

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

@Component
public class AMD implements CPU {

    @Value("R7")
    private String name;

    @Override
    public String toString() {
        return "AMD{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

输出结果如下:

Computer{name='小米', cpu='R7'}

使用java类写spring配置

使用@Configuration注解,自动扫描配置使用@ComponentScan注解
在测试类中使用AnnotationConfigApplicationContext对象导入配置类,见下例

示例

SpringScanConfig.java

package com.scan;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.scan")
public class SpringScanConfig {
}

TestScan.java

package com.scan;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestScan {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringScanConfig.class);
        Computer computer = (Computer) ac.getBean("com");

        System.out.println(computer);
    }
}

代理模式

代理模式:代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。

静态代理:目标类和代理类有相同的接口
动态代理:代理类是动态生成的,目标类和代理类可以没有相同的接口

静态代理简单示例

Star.java

package com.zr.proxy;

public interface Star {
    //赚钱
    void makeMoney(int money);

    //秀恩爱
    void showLove();
}

BaoQiang.java

package com.zr.proxy;

public class BaoQiang implements Star{
    @Override
    public void makeMoney(int money) {
        System.out.println("宝强赚了"+money+"钱,宝强笑嘿嘿");
    }

    @Override
    public void showLove() {
        System.out.println("宝强秀恩爱,别人都羡慕");
    }
}

SongZhe.java

package com.zr.proxy;

import java.util.Random;

public class SongZhe implements Star{

    private Star star;

    public SongZhe(Star star) {
        this.star = star;
    }

    @Override
    public void makeMoney(int money) {
        System.out.println("宋喆抽成500....");
        star.makeMoney(money);
    }

    @Override
    public void showLove() {
        boolean r = new Random().nextBoolean();
        if(r){
            star.showLove();
        }
        else{
            System.out.println("宋喆偷偷找马蓉");
        }
    }
}

TestStar.java

package com.zr.proxy;

import org.junit.Test;

public class TestStar {
    @Test
    public void star(){
        BaoQiang baoQiang = new BaoQiang();
        SongZhe songZhe = new SongZhe(baoQiang);
        songZhe.makeMoney(1000);
        songZhe.showLove();

    }
}

运行结果

宋喆抽成500....
宝强赚了1000钱,宝强笑嘿嘿
宝强秀恩爱,别人都羡慕

动态代理示例

TestStar.java

    @Test
    public void myStar(){
        //生成被代理类对象
        Star star = new BaoQiang();
        //生成代理类对象
        Star proxy = (Star) Proxy.newProxyInstance(star.getClass().getClassLoader(), star.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(proxy.getClass().getName());
                if(method.getName().equals("makeMoney")){
                    args[0] = 1000;
                }
                return method.invoke(star, args);
            }
        });
        proxy.makeMoney(2000);
        System.out.println("proxy==>" + proxy.getClass().getName());
    }

java注解

定义一个注解

MyWeb.java

package com.zr.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 定义一个注解
 */
//以下为元注解
@Target({ElementType.TYPE, ElementType.METHOD}) //修饰的注解能放到java类和方法的某一位置
@Retention(RetentionPolicy.RUNTIME) //注解的生效范围(RUNTIME指运行时生效)
public @interface MyWeb {
    String value() default "";
    String [] url() default {};
}

TestWeb.java

package com.zr.annotation;

import org.junit.Test;

public class TestWeb {
    @Test
    public void test(){
        //tomcat收到前端请求 /user/web, 需要判断交给哪个servlet来处理
        //tomcat遍历所有类,判断哪些类加了 MyWeb注解
        Class<?> clazz = UserWeb.class;
        MyWeb myWeb = clazz.getAnnotation(MyWeb.class);
        System.out.println(myWeb.value());
        //tomcat发现UserWeb类的MyWeb注解,value属性值和/user/web匹配,进入后续处理....
    }
}

AOP (面向切面编程)

AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充

切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务和日志管理是 J2EE 应用中一个关于横切关注点的很好的例子。 在 Spring AOP 中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 标注(@AspectJ 风格)来实现;

示例

spring-aop.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="man" class="com.aop.Man"></bean>
    <bean id="fbi" class="com.aop.FBI"></bean>
    <aop:config>
<!-- 切面规则   执行在Man的任意方法,参数为任意-->
        <aop:pointcut id="pointcut" expression="execution(* com.aop.Man.*(..))"/>
        <aop:aspect ref="fbi">
<!--            fbi这个bean的before方法 :before为前置通知-->
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>

FBI.java

package com.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

import java.util.Arrays;

public class FBI {
    public void before(JoinPoint joinPoint){
        Object obj =  joinPoint.getTarget();
        System.out.println("目标对象: "+ obj.getClass().getName());
        Object[] args = joinPoint.getArgs();
        System.out.println("目标对象方法参数: "+ Arrays.toString(args));
        Signature signature = joinPoint.getSignature();
        System.out.println("目标对象的方法: "+signature.getName());
    }
}

Man.java

package com.aop;

public class Man {
    private String name = "大壮";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void qq(String toName){
        System.out.println(this.name + "在和[" + toName + "]聊QQ");
    }

    public void  mm(){
        System.out.println(this.name + "在聊MM");
    }
}

TestAop.java

package com.aop;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAop {
    private ClassPathXmlApplicationContext ac;

    @Before
    public void init(){
        ac = new ClassPathXmlApplicationContext("spring-aop.xml");
    }
    @Test
    public void testBefore(){
        Man man = ac.getBean(Man.class);
        man.qq("小美");
        man.mm();
    }
    @After
    public void destroy(){
        ac.close();
    }
}

输出结果:

目标对象: com.aop.Man
目标对象方法参数: [小美]
目标对象的方法: qq
大壮在和[小美]聊QQ
目标对象: com.aop.Man
目标对象方法参数: []
目标对象的方法: mm
大壮在聊MM

alt alt alt alt