springAOP之framework包的解读(二)

来源:互联网 发布:汉语拼音拼读软件 编辑:程序博客网 时间:2024/05/15 22:46

ProxyFactory

package org.springframework.aop.framework;import org.aopalliance.intercept.Interceptor;import org.springframework.aop.TargetSource;import org.springframework.util.ClassUtils;/** * 规范的AOP代理工厂,而不是通过一个bean工厂 * 该类提供了一个简单的方法用代码获取我配置AOP代理 */@SuppressWarnings("serial")public class ProxyFactory extends ProxyCreatorSupport {    /**  创建一个ProxyFactory */    public ProxyFactory() {    }    /**     * 创建一个新的ProxyFactory。根据给定的目标实现将代理所有的接口     * @param target 代理的目标对象     */    public ProxyFactory(Object target) {        setTarget(target);        setInterfaces(ClassUtils.getAllInterfaces(target));    }    /**     * 创建一个新的ProxyFactory。无目标对象,只有接口。必须添加拦截器     * @param proxyInterfaces 代理必须实现的接口     */    public ProxyFactory(Class<?>... proxyInterfaces) {        setInterfaces(proxyInterfaces);    }    /**     * 根据给定的接口和拦截器创建一个新的ProxyFactory。     * 方便的方法去创建一个单独拦截器的代理,假定拦截器处理本身所有的调用,而不是委托目标对象,例如远程代理。     * @param proxyInterface 代理必须实现的接口     * @param interceptor 代理必须调用的拦截器     */    public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {        addInterface(proxyInterface);        addAdvice(interceptor);    }    /**     * 根据具体的TargetSource创建建一个ProxyFactory,使代理实现具体的接口。     * @param proxyInterface 代理必须实现的接口     * @param targetSource 代理必须调用的目标源(TargetSource)     */    public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {        addInterface(proxyInterface);        setTargetSource(targetSource);    }    /**     * 根据工厂的设置创建一个新的代理     * 可以重复调用。如果我们添加或删除接口,效果会不同。可以添加和删除拦截器。     * 使用默认的类加载器:通常,线程上下文类加载器(代理创建需要时)     * @return 代理的对象     */    public Object getProxy() {        return createAopProxy().getProxy();    }    /**     * 根据当前工厂的设置创建新的代理。可以重复调用。如果我们添加或删除接口,效果会不同。可以添加和删除拦截器。     * 使用给定的类载器(代理创建需要时)     * @param classLoader 类加载器,用于创建默认低级别代理功能的代理     * @return 代理的对象     */    public Object getProxy(ClassLoader classLoader) {        return createAopProxy().getProxy(classLoader);    }    /**     * 根据给定的接口和拦截器创建新的代理。方便的方法去创建单独拦截器的代理,假定拦截器处理自身所有的调用,而不是委托目标对象,例如远程代理。     * @param proxyInterface 代理必须实现的接口     * @param interceptor 代理必须调用的拦截器     * @return 代理的对象     * @see #ProxyFactory(Class, org.aopalliance.intercept.Interceptor)     */    @SuppressWarnings("unchecked")    public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {        return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();    }    /**     * 创建代理,利用指定的目标源,并实现具体的接口     * @param proxyInterface 代理必须实现的接口     * @param targetSource 代理必须调用的目标源     * @return 代理的对象     */    @SuppressWarnings("unchecked")    public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {        return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();    }    /**     * 创建代理,利用TargetSource的继承类     * @param targetSource 代理必须调用的目标源     * @return 代理的对象     */    public static Object getProxy(TargetSource targetSource) {        if (targetSource.getTargetClass() == null) {            throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");        }        ProxyFactory proxyFactory = new ProxyFactory();        proxyFactory.setTargetSource(targetSource);        proxyFactory.setProxyTargetClass(true);        return proxyFactory.getProxy();    }}

类ProxyFactoryBean

package org.springframework.aop.framework;import java.io.IOException;import java.io.ObjectInputStream;import java.io.Serializable;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import org.aopalliance.aop.Advice;import org.aopalliance.intercept.Interceptor;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.aop.Advisor;import org.springframework.aop.TargetSource;import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;import org.springframework.aop.framework.adapter.UnknownAdviceTypeException;import org.springframework.aop.target.SingletonTargetSource;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanClassLoaderAware;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.BeanFactoryUtils;import org.springframework.beans.factory.FactoryBean;import org.springframework.beans.factory.FactoryBeanNotInitializedException;import org.springframework.beans.factory.ListableBeanFactory;import org.springframework.core.OrderComparator;import org.springframework.util.ClassUtils;import org.springframework.util.ObjectUtils;/** * FactoryBean的实现,基于Spring的BeanFactory构造一个AOP代理。 * MethodInterceptors和Advisors当前bean工厂的一系列bean的名称确定,通过指定interceptorNames属性。 * 列表的最后一个入口(entry)可以为目标bean的名称或TargetSource;然而,通常有更好的代替方式:使用属性"targetName"/"target"/"targetSource" * 全局的拦截器和顾问能够以工厂的级别添加。指定的拦截器和顾问在拦截列表中被扩展, * 利用列表中入口:"xxx*",根据前缀的bean名称进行匹配(例如:"global*"匹配"globalBean1" 和 "globalBean2","*"匹配所有定义的拦截器)。 * 匹配的拦截器根据它们返回的顺序值被应用,如果它们实现了Ordered接口。 * 当代理接口有提供,创建一个JDK代理,若没有,则创建一个实际目标类的CGLIB代理. * 后者会工作,当且仅当目标类不拥有final方法,而动态的子类会在运行时被创建 * 从当前工厂获取的通知(Advised)可以被强转为代理,或者获取ProxyFactoryBean的引用并以编程的方法操控它(代理)。 * 当存在独立的原型引用,该bean不会工作。然而,它将会以原型工作,随后从工厂获得。 * 改变拦截器,会使单例(包括已存在的引用)立即生效。然而,改变接口或目标对象,则需要从工厂获取新的实例。 * 这意味着从工厂获取的单实例没有相同的对象ID,不过,它们有相同的拦截器和目标对象,改变任何引用,将会改变所有对象。 */@SuppressWarnings("serial")public class ProxyFactoryBean extends ProxyCreatorSupport        implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {    /**     * 拦截器列表的前缀值,表示全局匹配     */    public static final String GLOBAL_SUFFIX = "*";    protected final Log logger = LogFactory.getLog(getClass());    private String[] interceptorNames;    private String targetName;    private boolean autodetectInterfaces = true;    private boolean singleton = true;    private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();    private boolean freezeProxy = false;    private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();    private transient boolean classLoaderConfigured = false;    private transient BeanFactory beanFactory;    /** Whether the advisor chain has already been initialized */    private boolean advisorChainInitialized = false;    /** 如果是单例,缓存该单例的代理实例 */    private Object singletonInstance;    /**     * 设置代理的接口名称。若没指定接口,实际类的CGLIB会被创建。     * 这个方法实际与setInterfaces()一样,但是反射了TransactionProxyFactoryBean的setProxyInterfaces方法     */    public void setProxyInterfaces(Class<?>[] proxyInterfaces) throws ClassNotFoundException {        setInterfaces(proxyInterfaces);    }    /**     * 设置通知/顾问的bean名称。该方法通常用来设置bean工厂的工厂bean。引用的bean必须为Interceptor\Advisor或者Advice类型。     * 列表的最后一个入口(entry)可以为工厂中的任意一个bean名称     * 如果既不是Advice,也不是Advisor,一个新的单例目标源被添加并包装它(这里的它指entry?)。     * 目标bean无法使用,当属性"target"or "targetSource" or "targetName"有设置,在这种情况下,属性interceptorNames数组必须只包含Advice/Advisor的bean名称。     * 指定一个目标bean当作interceptorNames列表的最终名称,这种行为是过时的,将在新的spring中被移除。使用属性"targetName"替代     */    public void setInterceptorNames(String... interceptorNames) {        this.interceptorNames = interceptorNames;    }    /**     * 设置目标bean的名称。在"interceptorNames"数组的最后指定目标对象的名称是可选的。     * 你也可以直接指定一个目标对象或才一个目标源对象,分别通过"target"/"targetSource"属性指定     */    public void setTargetName(String targetName) {        this.targetName = targetName;    }    /**     * 自动检查代理接口,若没指定。默认为true,关闭这个标志用来创建一个CGLIB代理,对于所有的目标对类,如果没有指定接口。     */    public void setAutodetectInterfaces(boolean autodetectInterfaces) {        this.autodetectInterfaces = autodetectInterfaces;    }    /**     * 设置单例属性。管理工厂总是返回相同的代理实例(说明是同一个目标对象),或者它总是返回一个新的原型实例,     * 表示目标和拦截器也可能是新的实例,如果它们是从原型的bean定义中获取的。在对象图中,该方法允许很友好的唯一、独立的控制     */    public void setSingleton(boolean singleton) {        this.singleton = singleton;    }    /**     * 指定AdvisorAdapterRegistry,默认为全局的AdvisorAdapterRegistry     */    public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {        this.advisorAdapterRegistry = advisorAdapterRegistry;    }    @Override    public void setFrozen(boolean frozen) {        this.freezeProxy = frozen;    }    /**     * 设置类加载器用来生成代理类,默认为bean类加载器,例如:控制BeanFactory加载所有bean类的类加载器     * 该方法可被重写,在指定的代理中。     */    public void setProxyClassLoader(ClassLoader classLoader) {        this.proxyClassLoader = classLoader;        this.classLoaderConfigured = (classLoader != null);    }    @Override    public void setBeanClassLoader(ClassLoader classLoader) {        if (!this.classLoaderConfigured) {            this.proxyClassLoader = classLoader;        }    }    @Override    public void setBeanFactory(BeanFactory beanFactory) {        this.beanFactory = beanFactory;        checkInterceptorNames();    }    /**     * 返回一个代理。客户端从工厂bean获取beans时调用。通过该工厂创建一个AOP代理的实例返回。     * 该实例将被缓存为单例,并且代理每一次的调用都创建     * @return 一个刷新的AOP代理,影响该工厂的当前状态     */    @Override    public Object getObject() throws BeansException {        initializeAdvisorChain();        if (isSingleton()) {            return getSingletonInstance();        }        else {            if (this.targetName == null) {                logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +                        "Enable prototype proxies by setting the 'targetName' property.");            }            return newPrototypeInstance();        }    }    /**     * 返回代理的类型。若单例已创建,则检查,     * 否则回退到代理的接口(如果只是单独的类型),或目标bean类型,或目标源的目标类。     */    @Override    public Class<?> getObjectType() {        synchronized (this) {            if (this.singletonInstance != null) {                return this.singletonInstance.getClass();            }        }        Class<?>[] ifcs = getProxiedInterfaces();        if (ifcs.length == 1) {            return ifcs[0];        }        else if (ifcs.length > 1) {            return createCompositeInterface(ifcs);        }        else if (this.targetName != null && this.beanFactory != null) {            return this.beanFactory.getType(this.targetName);        }        else {            return getTargetClass();        }    }    @Override    public boolean isSingleton() {        return this.singleton;    }    /**     * 根据给定的接口创建组合接口类,在单独的类里实现给定的接口。     * 默认的实现为给这的接口构造一个JDK代理类。     * @param interfaces 合并的接口     * @return 合并后的接口类     */    protected Class<?> createCompositeInterface(Class<?>[] interfaces) {        return ClassUtils.createCompositeInterface(interfaces, this.proxyClassLoader);    }    /**     * 返回该类的代理对象的单例,如果还没被创建,则延迟创建。     * @return 共享的单例代理     */    private synchronized Object getSingletonInstance() {        if (this.singletonInstance == null) {            this.targetSource = freshTargetSource();            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {                // Rely on AOP infrastructure to tell us what interfaces to proxy.                Class<?> targetClass = getTargetClass();                if (targetClass == null) {                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");                }                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));            }            // Initialize the shared singleton instance.            super.setFrozen(this.freezeProxy);            this.singletonInstance = getProxy(createAopProxy());        }        return this.singletonInstance;    }    /**     * 创建一个该类已创建的代理对象的原型实例,依靠独立的AdvisedSupport配置。     * @return 一个完全独立的代理,独立操作通知(adivce)     */    private synchronized Object newPrototypeInstance() {        // 对于一个原型来说,我们需要提供代理,该代理为一个配置独立的实例        // 在这种情况下,该对象配置的实例不会有代理,但有一个单独的拷贝        if (logger.isTraceEnabled()) {            logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);        }        ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());        // The copy needs a fresh advisor chain, and a fresh TargetSource.        TargetSource targetSource = freshTargetSource();        copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {            // Rely on AOP infrastructure to tell us what interfaces to proxy.            copy.setInterfaces(                    ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader));        }        copy.setFrozen(this.freezeProxy);        if (logger.isTraceEnabled()) {            logger.trace("Using ProxyCreatorSupport copy: " + copy);        }        return getProxy(copy.createAopProxy());    }    /**     * 返回暴露的代理对象     * 默认实现以工厂的bean类加载器调用getProxy()。指定一个自定义的类加载器可以被重写     * @param aopProxy 事先准备好的AopProxy实例,用于获取代理     * @return 暴露的代理对象     */    protected Object getProxy(AopProxy aopProxy) {        return aopProxy.getProxy(this.proxyClassLoader);    }    /**     * 检查interceptorNames列表,是否包括最后元素的目标名称,若找到,删除并设置为targetName     */    private void checkInterceptorNames() {        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            String finalName = this.interceptorNames[this.interceptorNames.length - 1];            if (this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                // The last name in the chain may be an Advisor/Advice or a target/TargetSource.                // Unfortunately we don't know; we must look at type of the bean.                if (!finalName.endsWith(GLOBAL_SUFFIX) && !isNamedBeanAnAdvisorOrAdvice(finalName)) {                    // The target isn't an interceptor.                    this.targetName = finalName;                    if (logger.isDebugEnabled()) {                        logger.debug("Bean with name '" + finalName + "' concluding interceptor chain " +                                "is not an advisor class: treating it as a target or TargetSource");                    }                    String[] newNames = new String[this.interceptorNames.length - 1];                    System.arraycopy(this.interceptorNames, 0, newNames, 0, newNames.length);                    this.interceptorNames = newNames;                }            }        }    }    /**     * 检查bean工厂元数据解决该bean的名称(interceptorNames列表)是一个Advisor或Advice,或者可能为目标对象。     * @param beanName 检查的bean名称     * @return 为Advisor or Advice返回true     */    private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) {        Class<?> namedBeanClass = this.beanFactory.getType(beanName);        if (namedBeanClass != null) {            return (Advisor.class.isAssignableFrom(namedBeanClass) || Advice.class.isAssignableFrom(namedBeanClass));        }        // Treat it as an target bean if we can't tell.        if (logger.isDebugEnabled()) {            logger.debug("Could not determine type of bean with name '" + beanName +                    "' - assuming it is neither an Advisor nor an Advice");        }        return false;    }    /**     * 创建顾问(拦截器)链。由BeanFactory产生的顾问在每次一个新的原型实例被添加时会刷新。     * 通过工厂API以编程的方法添加的拦截器不会因这些改变(哪些改变?)而生效     */    private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            // Globals can't be last unless we specified a targetSource using the property...            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // Materialize interceptor chain from bean names.            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // If we get here, we need to add a named interceptor.                    // We must check if it's a singleton or prototype.                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.                        advice = this.beanFactory.getBean(name);                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }    /**     * 返回独立的顾问链。每次一个新的原型实例返回,我们调用该方法,     * 返回不同的原型的Advisors和Advices实例     */    private List<Advisor> freshAdvisorChain() {        Advisor[] advisors = getAdvisors();        List<Advisor> freshAdvisors = new ArrayList<Advisor>(advisors.length);        for (Advisor advisor : advisors) {            if (advisor instanceof PrototypePlaceholderAdvisor) {                PrototypePlaceholderAdvisor pa = (PrototypePlaceholderAdvisor) advisor;                if (logger.isDebugEnabled()) {                    logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");                }                // Replace the placeholder with a fresh prototype instance resulting                // from a getBean() lookup                if (this.beanFactory == null) {                    throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                            "- cannot resolve prototype advisor '" + pa.getBeanName() + "'");                }                Object bean = this.beanFactory.getBean(pa.getBeanName());                Advisor refreshedAdvisor = namedBeanToAdvisor(bean);                freshAdvisors.add(refreshedAdvisor);            }            else {                // Add the shared instance.                freshAdvisors.add(advisor);            }        }        return freshAdvisors;    }    /**     * 添加所有的全局拦截器和切入点     */    private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {        String[] globalAdvisorNames =                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);        String[] globalInterceptorNames =                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);        List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length);        Map<Object, String> names = new HashMap<Object, String>(beans.size());        for (String name : globalAdvisorNames) {            Object bean = beanFactory.getBean(name);            beans.add(bean);            names.put(bean, name);        }        for (String name : globalInterceptorNames) {            Object bean = beanFactory.getBean(name);            beans.add(bean);            names.put(bean, name);        }        OrderComparator.sort(beans);        for (Object bean : beans) {            String name = names.get(bean);            if (name.startsWith(prefix)) {                addAdvisorOnChainCreation(bean, name);            }        }    }    /**     * 当通知链创建时调用。添加advice、advisor、对象其他目标对象到拦截器列表。     * 因为有三个可能性,我们不能定义更强的类型     * @param next advice, advisor or target object     * @param name 在我们自己的bean工厂获取的目标对象的bean名称     */    private void addAdvisorOnChainCreation(Object next, String name) {        // We need to convert to an Advisor if necessary so that our source reference        // matches what we find from superclass interceptors.        Advisor advisor = namedBeanToAdvisor(next);        if (logger.isTraceEnabled()) {            logger.trace("Adding advisor with name '" + name + "'");        }        addAdvisor(advisor);    }    /**     * 创建代理时,返回的目标源。在interceptorNames列表的最后,目标没指定,TargetSource将成为这个类的TargetSource成员。     * 否则,我们获取目标,而且如果需要,将它包装为TargetSource     */    private TargetSource freshTargetSource() {        if (this.targetName == null) {            if (logger.isTraceEnabled()) {                logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");            }            return this.targetSource;        }        else {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve target with name '" + this.targetName + "'");            }            if (logger.isDebugEnabled()) {                logger.debug("Refreshing target with name '" + this.targetName + "'");            }            Object target = this.beanFactory.getBean(this.targetName);            return (target instanceof TargetSource ? (TargetSource) target : new SingletonTargetSource(target));        }    }    /**     * 通过在interceptorNames数组内调用getBean()生产的对象转化为Advisor或TargetSource     */    private Advisor namedBeanToAdvisor(Object next) {        try {            return this.advisorAdapterRegistry.wrap(next);        }        catch (UnknownAdviceTypeException ex) {            // We expected this to be an Advisor or Advice,            // but it wasn't. This is a configuration error.            throw new AopConfigException("Unknown advisor type " + next.getClass() +                    "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +                    "which may also be target or TargetSource", ex);        }    }    /**     * 清除并重新生成单例,当通知改变时     */    @Override    protected void adviceChanged() {        super.adviceChanged();        if (this.singleton) {            logger.debug("Advice has changed; recaching singleton instance");            synchronized (this) {                this.singletonInstance = null;            }        }    }    //---------------------------------------------------------------------    // Serialization support    //---------------------------------------------------------------------    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {        // Rely on default serialization; just initialize state after deserialization.        ois.defaultReadObject();        // Initialize transient fields.        this.proxyClassLoader = ClassUtils.getDefaultClassLoader();    }    /**     * 在拦截器链中使用,当我们在创建一个代理时需要用原型替代一个bean.     */    private static class PrototypePlaceholderAdvisor implements Advisor, Serializable {        private final String beanName;        private final String message;        public PrototypePlaceholderAdvisor(String beanName) {            this.beanName = beanName;            this.message = "Placeholder for prototype Advisor/Advice with bean name '" + beanName + "'";        }        public String getBeanName() {            return beanName;        }        @Override        public Advice getAdvice() {            throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);        }        @Override        public boolean isPerInstance() {            throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);        }        @Override        public String toString() {            return this.message;        }    }}
0 0