目录

一、Bean的自动装配

1.byName和byType装配

2.使用注解实现装配

@Autowired

@Resource

二、使用注解开发

三、代理模式

静态代理

动态代理

四、AOP

1、aop在spring中的作用

第一种方式

第二种方式实现aop

第三种方式,使用注解


一、Bean的自动装配

  • 自动装配是Spring满足bean依赖一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

在Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean【重要】

1.byName和byType装配

<bean id="cat" class="com.kun.pojo.Cat"></bean>
    <bean id="dog" class="com.kun.pojo.Dog"></bean>
<!--    byName会自动在容器上下文查找,和自己set方法后面的值对应的beanId
        byType找对象相同的对象属性

-->
    <bean id="people" class="com.kun.pojo.People" autowire="byType">
        <property name="name" value="带鱼"/>
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
        
    </bean>

2.使用注解实现装配

1.导入约束

2.配置注解的支持

<?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
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired

直接在属性上使用或者在set方法上使用,使用了以后可以不用写set方法了,且符合byType。

<!--开通注解支持-->
    <context:annotation-config/>
@Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

科普:@Nullable    字段标记的注解,说明这个值可以为空

        如果autowired,require为false表示允许cat在容器中不存在

提过自动装配有多个或者复杂,无法匹配用

@Autowired
    @Qualifier(value = "dog22")
    private Dog dog;

@Resource

先匹配名字在匹配类型

可以加name属性里的value值确定装配

两者的区别:

  • 都是用来自动装配的
  • autowired用过bytype
  • resource默认通过byname方式,如果找不到在通过byType

二、使用注解开发

必须导入aop包,使用注解需要导入context约束,增加注解的支持

<!--指定要扫描的包,这个包下的注解生效-->
    <context:component-scan base-package="com.kun.pojo"/>
    <!--开通注解支持-->
    <context:annotation-config/>

1、bean

2、属性注入😊😊

//等价于<bean id="user" class="com.kun.pojo.User">
@Component
public class User {
//    等价于<property name="user" value="带鱼"/>
    @Value("带鱼")
    public String name;
}

3、衍生注解

@Component有几个衍生注解

  • dao层【@Repository】
  • service层 【@Service】
  • controller层  【@Controller】
  • 这四个注解功能都是一样的,代表将某个类注册到bean

4、自动装配置

5、作用域

@Scope("singleton")     单例模式

6、小结

        xml与注解

7、使用java的方式配置Spring

        我们不需要Spring的xml配置,完全交给java

        javaconfig是spring的子项目        

编写User类

@Component
public class User {
    public String name;

    public String getName() {
        return name;
    }
    @Value("带鱼")
    public void setName(String name) {
        this.name = name;
    }

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

用Config类代替bean

package com.kun.config;


import com.kun.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration    //这个也会被spring托管
public class Config {

    @Bean
    public User getUser(){
        return new User();
    }
}

测试

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

        User getUser = context.getBean("getUser", User.class);
        System.out.println(getUser.getName());

    }
}

三、代理模式

静态代理

抽象角色:接口或者抽象类

public interface Rent {
    public void rent();
}

真实角色

public class Host implements Rent{
    public void rent() {
        System.out.println("房东出租房子");
    }
}

代理角色

public class Proxy implements Rent{

    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;

    }

    public void rent() {
        host.rent();
        fare();
    }
//    看房
    public void fare(){
        System.out.println("收费");
    }
}

客户

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
//中介收房租    还有代理的函数方法
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式的好处:

  • 可以使真实的操作更加纯粹,不用去管其他业务
  • 公共交给代理角色,实现了业务的分工
  • 公共业务放生扩展时,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理类:效率低

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是直接写好的
  • 动态代理分为两大类:基于接口,基于类
  • 基于接口——JDK动态代理
  • 基于类:cglib
  • java字节实现:javasist

需要了解两个类:Proxy:代理、InvocationHandler:调用

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {
//    被代理的接口
    private Rent rent;
    public void setRent(Rent rent) {
        this.rent = rent;
    }
    //    生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }
//处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        fare();
//        动态代理的本质  用的反射
        Object invoke = method.invoke(rent, args);
        qian();
        return invoke;
    }

    public void fare(){
        System.out.println("中介收费");
    }
    public void qian(){
        System.out.println("中介签合同");
    }
}
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
        proxyInvocationHandler.setRent(host);

        Rent proxy = (Rent) proxyInvocationHandler.getProxy();   //动态生成的
        proxy.rent();
    }
}

万能工具类

public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;
 
    public void setTarget(Object target) {
        this.target = target;
    }
 
    //生成代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }
 
    // proxy : 代理类
    // method : 代理类的调用处理程序的方法对象.
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
 
    public void log(String methodName){
        System.out.println("执行了"+methodName+"方法");
    }
 
}
public class Test {
    public static void main(String[] args) {
        //真实对象
        UserServiceImpl userService = new UserServiceImpl();
        //代理对象的调用处理程序
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService); //设置要代理的对象
        UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
        proxy.delete();
    }
}

动态代理的好处

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .
  • 一个动态代理 , 一般代理某一类业务
  • 一个动态代理可以代理多个类,代理的是接口!

四、AOP

1、aop在spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:日志,缓存,事务
  • 切面(Aspect):横切关注点被模块化的对象,即(Log类)
  • 通知(Advice):切面必须要完成的工作。即(Log的一个方法)
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知执行的地点的定义
  • 连接点(JointPoint):与切入点匹配的执行点

使用aop需要导报

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

第一种方式

编写业务接口和实现类

public interface UserService {
 
    public void add(); 
    public void delete();
    public void update(); 
    public void search();
 
}
public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void select() {
        System.out.println("查询了一个用户");
    }
}

编写增强类

public class Log implements MethodBeforeAdvice {
//   要执行目标对象的方法
//    object参数
//    target  目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName());
    }
}
public class AfterLog implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行力"+method.getName()+"返回了结果"+returnValue);
    }
}

去注册,并实现aop的切入,注意导入约束

<bean id="userService" class="com.kun.service.UserServiceImpl"/>
    <bean id="log" class="com.kun.log.Log"/>
    <bean id="afterLog" class="com.kun.log.AfterLog"/>
<!--    方式一-->
    <!--配置aop-->
    <aop:config>
    <!--        切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.kun.service.UserServiceImpl.*(..))"/>
    <!--        执行环绕-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

测试

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//        动态代理的是接口或者抽象类
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

第二种方式实现aop

业务接口和实现类不变

第一步,编写切入类

public class DiyPointCut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}
<bean id="diy" class="com.kun.diy.DiyPointCut"/>
    <aop:config>
        <aop:aspect ref="diy">
            <aop:pointcut id="pointcut" expression="execution(* com.kun.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

第三种方式,使用注解

业务接口和实现类不变

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
 
@Aspect
public class AnnotationPointcut {
    @Before("execution(* com.kun.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("---------方法执行前---------");
    }
 
    @After("execution(* com.kun.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("---------方法执行后---------");
    }
 
    @Around("execution(* com.kun.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        System.out.println("签名:"+jp.getSignature());
        //执行目标方法proceed
        Object proceed = jp.proceed();
        System.out.println("环绕后");
        System.out.println(proceed);
    }
}
//结果为 先环绕 后 执行方法前 在 执行方法
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>