我需要能够标记方法,以便在多次调用它们时抛出RuntimeException.
我试图强制执行一些单一的赋值语义,并且我的类的参数数量太大而无法放入单个构造函数中,我需要能够使这些类JAXB也被识别,因此对象需要是可变的但我想要强制执行单一赋值语义.
我很确定我可以用Aspects做到这一点,但我真的希望能够使用我自己的Annotations处理器.
我知道如何使用Python中的装饰器来做到这一点.
如何编写一个Annotation处理器,它可以在运行时拦截对带注释方法的调用,而不仅仅是在编译时?
我认为我正在使用Dynamic Proxies拦截方法调用,我只需要弄清楚如何将它们与我的Annotation处理器集成.
动态代理需要你使用一个接口,这是繁琐的方式,我现在有一个CGLib MethodInterceptor工作,更少的要求截获和装饰,以牺牲添加依赖为代价.
我有史以来第一次使用标准JDK动态代理实现自己的代理类.它的工作原理相当不错,除了一个细节:equals(...)方法.
我们假设我们有一个像这样的简单接口,我们要代理它:
public interface MyInterface {
public String getID();
public void setID(String id);
}
Run Code Online (Sandbox Code Playgroud)
......我们的实现看起来是这样的(标准的Java Bean与生成hashCode()和equals):
public class MyImplementation implements MyInterface {
private String id;
public String getID() { return this.id; }
public void setID(String id) { this.id = id; }
// hash code & equals generated by eclipse
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (this.databaseId == null ? 0 : …Run Code Online (Sandbox Code Playgroud) 当使用Spring AOP使用NameMatchMethodPointcutAdvisor和BeanNameAutoProxyCreator为类创建代理时,这实际上代理了对该对象的每次调用,但仅将建议应用于匹配的方法,或者以某种方式创建仅具有这些方法并使用正常的Proxied对象应该被截获的呼叫的对象?
方式,我想我明白它确实代理了对对象的每次调用,但后来只调用匹配方法的顾问 - 但我找不到一个好的例子/帖子来确认这一点.
我想拥有可以用我自己的自定义属性装饰的属性 getter 和方法,并根据该属性的存在用不同的实现替换方法主体。此外,不同的实现将需要知道赋予自定义属性的构造函数参数,它装饰方法。
这显然可以用 AOP 来完成,比如 PostSharp 或 LinFu,但我想知道是否有一种方法可以做到这一点,而不涉及构建后处理步骤,因为添加这比我更喜欢的项目复杂化。
如何在不创建实现它的类的情况下为接口创建代理?
我有一个具体的例子:我有一个接口,Contact,需要创建一个充当联系人的代理对象.此代理对象将用于运行一些TestNG测试.
我尝试过使用JDK方法,但只能找到需要实际实现该接口的示例.
我还发现jasssist可以帮助我解决这个问题,并尝试实现一个似乎有效的简单示例,直到我出现Out of Memory错误.这是我正在做的事情的片段:
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory
protected final T createMock(final Class<T> clazz) {
final ProxyFactory factory = new ProxyFactory();
factory.setInterfaces(new Class[] { clazz });
factory.setFilter(new MethodFilter() {
public final boolean isHandled(final Method m) {
// ignore finalize()
return !m.getName().equals("finalize");
}
});
final MethodHandler handler = createDefaultMethodHandler();
try {
return (T) factory.create(new Class<?>[0], new Object[0], handler);
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
private MethodHandler createDefaultMethodHandler() {
return new MethodHandler() { …Run Code Online (Sandbox Code Playgroud) 假设有一个接口Subject.
interface Subject { void request(); }
Run Code Online (Sandbox Code Playgroud)
我们有一个RealSubject类.假设我们想要增强RealSubject,我们可以使用包裹RealSubject的代理模式:
class Proxy implements Subject {
private RealSubject ref;
void request(){ ... }
}
Run Code Online (Sandbox Code Playgroud)
或者我们可以扩展RealSubject并覆盖该方法
class EnhancedSubject extends RealSubject {
@Override
void request() { ... }
}
Run Code Online (Sandbox Code Playgroud)
哪种方法更好?我知道Liskov原则; 让我们假设EnhancedSubject满足Liskov原则.你还在考虑继承吗?
如果没有接口Subject(即,RealSubject没有实现任何接口),似乎"inherit and override"是唯一的选项,因为在Proxy模式中没有要实现的接口.如果没有主题界面,您仍然可以应用代理模式吗?
我需要在C#中创建动态代理.我希望这个类包装另一个类,并采用它的公共接口,转发对这些函数的调用:
class MyRootClass
{
public virtual void Foo()
{
Console.Out.WriteLine("Foo!");
}
}
interface ISecondaryInterface
{
void Bar();
}
class Wrapper<T> : ISecondaryInterface where T: MyRootClass
{
public Wrapper(T otherObj)
{
}
public void Bar()
{
Console.Out.WriteLine("Bar!");
}
}
Run Code Online (Sandbox Code Playgroud)
这是我想要使用它的方式:
Wrapper<MyRootClass> wrappedObj = new Wrapper<MyRootClass>(new MyRootClass());
wrappedObj.Bar();
wrappedObj.Foo();
Run Code Online (Sandbox Code Playgroud)
生产:
Bar!
Foo!
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
最简单的方法是什么?
最好的方法是什么?
非常感谢.
UPDATE
我尝试遵循Wernight的建议并使用C#4.0动态代理实现此功能.不幸的是,我仍然被卡住了.代理的要点是模仿通常(通常是)预期的其他接口.使用DynamicObject要求我将其所有客户端更改为使用"dynamic"而不是"ISecondaryInterface".
有没有办法获取代理对象,这样当它包装A时,它会(静态地)通告它支持A的接口; 当它包装B时,它会宣传支持B的界面?
更新2
例如:
class MySecretProxy : DynamicObject, ISecondaryInterface
{
public override void TryInvokeMember(...) { .. }
// no declaration of Bar -- let …Run Code Online (Sandbox Code Playgroud) 我尝试使用Sun在其“ 代理使用情况”页面上发布的代码 ,并且尝试使用DebugProxy打印调用的方法。问题是,我要为其创建代理的对象需要有一个参数。如果尝试使用构造函数的参数创建代理,则会收到以下错误:
线程“主”中的异常java.lang.ClassCastException:$ Proxy0无法转换为myPackage.myClass
我创建了这样的代理:
MyClass mc = (MyClass) DebugProxy.newInstance(new MyClass(props));
Run Code Online (Sandbox Code Playgroud)
如何创建代理实例,并仍然调用正确的构造函数?
今天,我java.lang.reflect.Proxy在科特林(Kotlin)和一些人一起玩耍,对此行为感到惊讶:
import java.lang.reflect.Proxy
interface Dog {
fun bark()
fun bark3Times()
}
class DogImpl : Dog {
override fun bark() = println("Bark!")
override fun bark3Times() = repeat(3) { bark() }
}
fun Dog.bark5Times() = repeat(5) { bark() }
fun main(args: Array<String>) {
val classLoader = Dog::class.java.classLoader
val realDog: Dog = DogImpl()
val proxyDog: Dog = Proxy.newProxyInstance(
classLoader,
arrayOf(Dog::class.java)
) { _, method, _ ->
println("Proxy invoked! Method = ${method.name}")
method.invoke(realDog)
} as Dog
println("--- Dog barking 3 times ---") …Run Code Online (Sandbox Code Playgroud) 我的问题是关于内部方法调用的 AOP Spring 行为。
@Service
class Service {
@Transactional
public void method1() {
method1();
}
@Transactional
public void method2() {}
}
Run Code Online (Sandbox Code Playgroud)
如果我们从外部调用method1(),method1()会以事务模式执行,但由于内部调用method2(),method2()内部的代码不会以事务模式执行。
同时,对于 Configuration 类,通常我们应该有相同的行为:
@Configuration
class MyConfiguration{
@Bean
public Object1 bean1() {
return new Object1();
}
@Bean
public Object1 bean2() {
Object1 b1 = bean1();
return new Object2(b1);
}
}
Run Code Online (Sandbox Code Playgroud)
通常,如果我理解得很好,从 bean2() 调用 bean1() 方法不应该被代理对象拦截,因此,如果我们多次调用 bean1(),我们每次都应该得到不同的对象。
首先,您能否从技术上解释为什么代理对象没有拦截内部调用,其次检查我对第二个示例的理解是否正确。
让我们考虑以下 bean:
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.INTERFACES)
public class MyBeanB implements MyBeanBInterface {
private static final AtomicLong COUNTER = new AtomicLong(0);
private Long index;
public MyBeanB() {
index = COUNTER.getAndIncrement();
System.out.println("constructor invocation:" + index);
}
@Transactional
@Override
public long getCounter() {
return index;
}
}
Run Code Online (Sandbox Code Playgroud)
并考虑两种不同的用法:
@Service
public class MyBeanA {
@Autowired
private MyBeanB myBeanB;
....
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,应用程序无法启动并打印:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'myBeanB' could not be injected as a 'my.pack.MyBeanB' because …Run Code Online (Sandbox Code Playgroud) Castle 项目 DynamicProxy 是否大量使用反射......就像不断?
或者它是否预先反射缓存数据?
dynamic-proxy ×12
java ×8
c# ×3
spring ×3
.net ×2
aop ×2
cglib ×2
proxy ×2
spring-aop ×2
.net-3.5 ×1
annotations ×1
castle ×1
equals ×1
jaxb ×1
kotlin ×1
mocking ×1
reflection ×1
spring-boot ×1